summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/angle/src
diff options
context:
space:
mode:
authorOliver Wolff <oliver.wolff@theqtcompany.com>2016-03-24 12:38:18 +0100
committerOliver Wolff <oliver.wolff@qt.io>2016-04-25 05:57:38 +0000
commite12ba07322cd61c5cf50c25ed8d1f08f6b1ff879 (patch)
treed31a44c9f123ed764a00eff7b4fff656a07d54ab /src/3rdparty/angle/src
parentd3dcc6f610b97be7cbfbb0a65988e5940568c825 (diff)
Update ANGLE to chromium/2651
Change-Id: I1cd32b780b1a0b913fab870e155ae1f4f9ac40d7 Reviewed-by: Maurice Kalinowski <maurice.kalinowski@qt.io>
Diffstat (limited to 'src/3rdparty/angle/src')
-rw-r--r--src/3rdparty/angle/src/common/BitSetIterator.h156
-rw-r--r--src/3rdparty/angle/src/common/Float16ToFloat32.cpp (renamed from src/3rdparty/angle/src/libANGLE/Float16ToFloat32.cpp)4
-rw-r--r--src/3rdparty/angle/src/common/Optional.h20
-rw-r--r--src/3rdparty/angle/src/common/angleutils.cpp7
-rw-r--r--src/3rdparty/angle/src/common/angleutils.h7
-rw-r--r--src/3rdparty/angle/src/common/debug.cpp6
-rw-r--r--src/3rdparty/angle/src/common/debug.h37
-rw-r--r--src/3rdparty/angle/src/common/event_tracer.cpp52
-rw-r--r--src/3rdparty/angle/src/common/event_tracer.h26
-rw-r--r--src/3rdparty/angle/src/common/mathutil.cpp12
-rw-r--r--src/3rdparty/angle/src/common/mathutil.h206
-rw-r--r--src/3rdparty/angle/src/common/matrix_utils.h349
-rw-r--r--src/3rdparty/angle/src/common/platform.h9
-rw-r--r--src/3rdparty/angle/src/common/string_utils.cpp136
-rw-r--r--src/3rdparty/angle/src/common/string_utils.h49
-rw-r--r--src/3rdparty/angle/src/common/utilities.cpp311
-rw-r--r--src/3rdparty/angle/src/common/utilities.h40
-rw-r--r--src/3rdparty/angle/src/common/version.h5
-rw-r--r--src/3rdparty/angle/src/compiler/preprocessor/DiagnosticsBase.cpp10
-rw-r--r--src/3rdparty/angle/src/compiler/preprocessor/DiagnosticsBase.h7
-rw-r--r--src/3rdparty/angle/src/compiler/preprocessor/DirectiveParser.cpp236
-rw-r--r--src/3rdparty/angle/src/compiler/preprocessor/DirectiveParser.h5
-rw-r--r--src/3rdparty/angle/src/compiler/preprocessor/ExpressionParser.h14
-rw-r--r--src/3rdparty/angle/src/compiler/preprocessor/ExpressionParser.y151
-rw-r--r--src/3rdparty/angle/src/compiler/preprocessor/Input.cpp66
-rw-r--r--src/3rdparty/angle/src/compiler/preprocessor/Input.h6
-rw-r--r--src/3rdparty/angle/src/compiler/preprocessor/Macro.cpp20
-rw-r--r--src/3rdparty/angle/src/compiler/preprocessor/Macro.h2
-rw-r--r--src/3rdparty/angle/src/compiler/preprocessor/MacroExpander.cpp68
-rw-r--r--src/3rdparty/angle/src/compiler/preprocessor/MacroExpander.h11
-rw-r--r--src/3rdparty/angle/src/compiler/preprocessor/Preprocessor.cpp25
-rw-r--r--src/3rdparty/angle/src/compiler/preprocessor/Tokenizer.h2
-rw-r--r--src/3rdparty/angle/src/compiler/preprocessor/Tokenizer.l17
-rw-r--r--src/3rdparty/angle/src/compiler/preprocessor/numeric_lex.h10
-rw-r--r--src/3rdparty/angle/src/compiler/translator/ASTMetadataHLSL.cpp451
-rw-r--r--src/3rdparty/angle/src/compiler/translator/ASTMetadataHLSL.h58
-rw-r--r--src/3rdparty/angle/src/compiler/translator/ArrayReturnValueToOutParameter.cpp206
-rw-r--r--src/3rdparty/angle/src/compiler/translator/ArrayReturnValueToOutParameter.h16
-rw-r--r--src/3rdparty/angle/src/compiler/translator/BaseTypes.h126
-rw-r--r--src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulator.cpp144
-rw-r--r--src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulator.h46
-rw-r--r--src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulatorGLSL.cpp162
-rw-r--r--src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulatorGLSL.h8
-rw-r--r--src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulatorHLSL.cpp47
-rw-r--r--src/3rdparty/angle/src/compiler/translator/Cache.cpp100
-rw-r--r--src/3rdparty/angle/src/compiler/translator/Cache.h90
-rw-r--r--src/3rdparty/angle/src/compiler/translator/CallDAG.cpp293
-rw-r--r--src/3rdparty/angle/src/compiler/translator/CallDAG.h75
-rw-r--r--src/3rdparty/angle/src/compiler/translator/CodeGen.cpp38
-rw-r--r--src/3rdparty/angle/src/compiler/translator/Common.h27
-rw-r--r--src/3rdparty/angle/src/compiler/translator/Compiler.cpp329
-rw-r--r--src/3rdparty/angle/src/compiler/translator/Compiler.h62
-rw-r--r--src/3rdparty/angle/src/compiler/translator/ConstantUnion.h60
-rw-r--r--src/3rdparty/angle/src/compiler/translator/Diagnostics.cpp7
-rw-r--r--src/3rdparty/angle/src/compiler/translator/Diagnostics.h8
-rw-r--r--src/3rdparty/angle/src/compiler/translator/DirectiveHandler.cpp20
-rw-r--r--src/3rdparty/angle/src/compiler/translator/DirectiveHandler.h31
-rw-r--r--src/3rdparty/angle/src/compiler/translator/EmulatePrecision.cpp127
-rw-r--r--src/3rdparty/angle/src/compiler/translator/EmulatePrecision.h26
-rw-r--r--src/3rdparty/angle/src/compiler/translator/ExtensionBehavior.h6
-rw-r--r--src/3rdparty/angle/src/compiler/translator/ExtensionGLSL.cpp100
-rw-r--r--src/3rdparty/angle/src/compiler/translator/ExtensionGLSL.h39
-rw-r--r--src/3rdparty/angle/src/compiler/translator/FlagStd140Structs.h10
-rw-r--r--src/3rdparty/angle/src/compiler/translator/ForLoopUnroll.cpp29
-rw-r--r--src/3rdparty/angle/src/compiler/translator/ForLoopUnroll.h15
-rw-r--r--src/3rdparty/angle/src/compiler/translator/Initialize.cpp123
-rw-r--r--src/3rdparty/angle/src/compiler/translator/InitializeDll.cpp4
-rw-r--r--src/3rdparty/angle/src/compiler/translator/InitializeParseContext.h2
-rw-r--r--src/3rdparty/angle/src/compiler/translator/InitializeVariables.cpp9
-rw-r--r--src/3rdparty/angle/src/compiler/translator/InitializeVariables.h17
-rw-r--r--src/3rdparty/angle/src/compiler/translator/IntermNode.cpp2366
-rw-r--r--src/3rdparty/angle/src/compiler/translator/IntermNode.h524
-rw-r--r--src/3rdparty/angle/src/compiler/translator/IntermTraverse.cpp660
-rw-r--r--src/3rdparty/angle/src/compiler/translator/Intermediate.cpp189
-rw-r--r--src/3rdparty/angle/src/compiler/translator/Intermediate.h22
-rw-r--r--src/3rdparty/angle/src/compiler/translator/NodeSearch.h25
-rw-r--r--src/3rdparty/angle/src/compiler/translator/Operator.cpp6
-rw-r--r--src/3rdparty/angle/src/compiler/translator/Operator.h7
-rw-r--r--src/3rdparty/angle/src/compiler/translator/OutputESSL.h3
-rw-r--r--src/3rdparty/angle/src/compiler/translator/OutputGLSL.cpp15
-rw-r--r--src/3rdparty/angle/src/compiler/translator/OutputGLSL.h6
-rw-r--r--src/3rdparty/angle/src/compiler/translator/OutputGLSLBase.cpp322
-rw-r--r--src/3rdparty/angle/src/compiler/translator/OutputGLSLBase.h31
-rw-r--r--src/3rdparty/angle/src/compiler/translator/OutputHLSL.cpp1568
-rw-r--r--src/3rdparty/angle/src/compiler/translator/OutputHLSL.h59
-rw-r--r--src/3rdparty/angle/src/compiler/translator/ParseContext.cpp3530
-rw-r--r--src/3rdparty/angle/src/compiler/translator/ParseContext.h473
-rw-r--r--src/3rdparty/angle/src/compiler/translator/PoolAlloc.h25
-rw-r--r--src/3rdparty/angle/src/compiler/translator/PruneEmptyDeclarations.cpp81
-rw-r--r--src/3rdparty/angle/src/compiler/translator/PruneEmptyDeclarations.h15
-rw-r--r--src/3rdparty/angle/src/compiler/translator/RecordConstantPrecision.cpp157
-rw-r--r--src/3rdparty/angle/src/compiler/translator/RecordConstantPrecision.h23
-rw-r--r--src/3rdparty/angle/src/compiler/translator/RegenerateStructNames.cpp2
-rw-r--r--src/3rdparty/angle/src/compiler/translator/RegenerateStructNames.h7
-rw-r--r--src/3rdparty/angle/src/compiler/translator/RemoveDynamicIndexing.cpp513
-rw-r--r--src/3rdparty/angle/src/compiler/translator/RemoveDynamicIndexing.h21
-rw-r--r--src/3rdparty/angle/src/compiler/translator/RemovePow.cpp105
-rw-r--r--src/3rdparty/angle/src/compiler/translator/RemovePow.h18
-rw-r--r--src/3rdparty/angle/src/compiler/translator/RenameFunction.h2
-rw-r--r--src/3rdparty/angle/src/compiler/translator/RewriteDoWhile.cpp163
-rw-r--r--src/3rdparty/angle/src/compiler/translator/RewriteDoWhile.h16
-rw-r--r--src/3rdparty/angle/src/compiler/translator/RewriteElseBlocks.cpp58
-rw-r--r--src/3rdparty/angle/src/compiler/translator/RewriteElseBlocks.h2
-rw-r--r--src/3rdparty/angle/src/compiler/translator/ScalarizeVecAndMatConstructorArgs.cpp22
-rw-r--r--src/3rdparty/angle/src/compiler/translator/ScalarizeVecAndMatConstructorArgs.h5
-rw-r--r--src/3rdparty/angle/src/compiler/translator/SearchSymbol.cpp4
-rw-r--r--src/3rdparty/angle/src/compiler/translator/SearchSymbol.h2
-rw-r--r--src/3rdparty/angle/src/compiler/translator/SeparateArrayInitialization.cpp92
-rw-r--r--src/3rdparty/angle/src/compiler/translator/SeparateArrayInitialization.h25
-rw-r--r--src/3rdparty/angle/src/compiler/translator/SeparateDeclarations.cpp77
-rw-r--r--src/3rdparty/angle/src/compiler/translator/SeparateDeclarations.h23
-rw-r--r--src/3rdparty/angle/src/compiler/translator/SeparateExpressionsReturningArrays.cpp169
-rw-r--r--src/3rdparty/angle/src/compiler/translator/SeparateExpressionsReturningArrays.h19
-rw-r--r--src/3rdparty/angle/src/compiler/translator/ShaderLang.cpp67
-rw-r--r--src/3rdparty/angle/src/compiler/translator/ShaderVars.cpp74
-rw-r--r--src/3rdparty/angle/src/compiler/translator/SymbolTable.cpp80
-rw-r--r--src/3rdparty/angle/src/compiler/translator/SymbolTable.h173
-rw-r--r--src/3rdparty/angle/src/compiler/translator/TranslatorESSL.cpp24
-rw-r--r--src/3rdparty/angle/src/compiler/translator/TranslatorESSL.h2
-rw-r--r--src/3rdparty/angle/src/compiler/translator/TranslatorGLSL.cpp159
-rw-r--r--src/3rdparty/angle/src/compiler/translator/TranslatorGLSL.h4
-rw-r--r--src/3rdparty/angle/src/compiler/translator/TranslatorHLSL.cpp36
-rw-r--r--src/3rdparty/angle/src/compiler/translator/TranslatorHLSL.h7
-rw-r--r--src/3rdparty/angle/src/compiler/translator/Types.cpp45
-rw-r--r--src/3rdparty/angle/src/compiler/translator/Types.h151
-rw-r--r--src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuitAST.cpp4
-rw-r--r--src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuitAST.h7
-rw-r--r--src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuitToIf.cpp368
-rw-r--r--src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuitToIf.h18
-rw-r--r--src/3rdparty/angle/src/compiler/translator/UniformHLSL.cpp128
-rw-r--r--src/3rdparty/angle/src/compiler/translator/UniformHLSL.h12
-rw-r--r--src/3rdparty/angle/src/compiler/translator/UtilsHLSL.cpp234
-rw-r--r--src/3rdparty/angle/src/compiler/translator/UtilsHLSL.h47
-rw-r--r--src/3rdparty/angle/src/compiler/translator/ValidateGlobalInitializer.cpp112
-rw-r--r--src/3rdparty/angle/src/compiler/translator/ValidateGlobalInitializer.h16
-rw-r--r--src/3rdparty/angle/src/compiler/translator/ValidateLimitations.cpp73
-rw-r--r--src/3rdparty/angle/src/compiler/translator/ValidateLimitations.h16
-rw-r--r--src/3rdparty/angle/src/compiler/translator/ValidateOutputs.cpp98
-rw-r--r--src/3rdparty/angle/src/compiler/translator/ValidateOutputs.h18
-rw-r--r--src/3rdparty/angle/src/compiler/translator/ValidateSwitch.h2
-rw-r--r--src/3rdparty/angle/src/compiler/translator/VariableInfo.cpp216
-rw-r--r--src/3rdparty/angle/src/compiler/translator/VariableInfo.h17
-rw-r--r--src/3rdparty/angle/src/compiler/translator/VersionGLSL.cpp59
-rw-r--r--src/3rdparty/angle/src/compiler/translator/VersionGLSL.h26
-rw-r--r--src/3rdparty/angle/src/compiler/translator/blocklayout.cpp5
-rw-r--r--src/3rdparty/angle/src/compiler/translator/blocklayout.h21
-rw-r--r--src/3rdparty/angle/src/compiler/translator/blocklayoutHLSL.cpp12
-rw-r--r--src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraph.cpp2
-rw-r--r--src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraph.h55
-rw-r--r--src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraphBuilder.h10
-rw-r--r--src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraphOutput.cpp3
-rw-r--r--src/3rdparty/angle/src/compiler/translator/glslang.h2
-rw-r--r--src/3rdparty/angle/src/compiler/translator/glslang.l97
-rw-r--r--src/3rdparty/angle/src/compiler/translator/glslang.y407
-rw-r--r--src/3rdparty/angle/src/compiler/translator/intermOut.cpp61
-rw-r--r--src/3rdparty/angle/src/compiler/translator/timing/RestrictFragmentShaderTiming.cpp10
-rw-r--r--src/3rdparty/angle/src/compiler/translator/timing/RestrictVertexShaderTiming.h3
-rw-r--r--src/3rdparty/angle/src/compiler/translator/util.cpp20
-rw-r--r--src/3rdparty/angle/src/compiler/translator/util.h9
-rw-r--r--src/3rdparty/angle/src/id/commit.h4
-rw-r--r--src/3rdparty/angle/src/libANGLE/AttributeMap.h8
-rw-r--r--src/3rdparty/angle/src/libANGLE/BinaryStream.h16
-rw-r--r--src/3rdparty/angle/src/libANGLE/Buffer.cpp91
-rw-r--r--src/3rdparty/angle/src/libANGLE/Buffer.h37
-rw-r--r--src/3rdparty/angle/src/libANGLE/Caps.cpp314
-rw-r--r--src/3rdparty/angle/src/libANGLE/Caps.h173
-rw-r--r--src/3rdparty/angle/src/libANGLE/Compiler.cpp114
-rw-r--r--src/3rdparty/angle/src/libANGLE/Compiler.h20
-rw-r--r--src/3rdparty/angle/src/libANGLE/Config.cpp8
-rw-r--r--src/3rdparty/angle/src/libANGLE/Config.h1
-rw-r--r--src/3rdparty/angle/src/libANGLE/Context.cpp1333
-rw-r--r--src/3rdparty/angle/src/libANGLE/Context.h176
-rw-r--r--src/3rdparty/angle/src/libANGLE/Data.cpp55
-rw-r--r--src/3rdparty/angle/src/libANGLE/Data.h48
-rw-r--r--src/3rdparty/angle/src/libANGLE/Debug.cpp303
-rw-r--r--src/3rdparty/angle/src/libANGLE/Debug.h120
-rw-r--r--src/3rdparty/angle/src/libANGLE/Debug2.cpp303
-rw-r--r--src/3rdparty/angle/src/libANGLE/Debug2.h120
-rw-r--r--src/3rdparty/angle/src/libANGLE/Device.cpp130
-rw-r--r--src/3rdparty/angle/src/libANGLE/Device.h58
-rw-r--r--src/3rdparty/angle/src/libANGLE/Display.cpp426
-rw-r--r--src/3rdparty/angle/src/libANGLE/Display.h28
-rw-r--r--src/3rdparty/angle/src/libANGLE/Error.cpp48
-rw-r--r--src/3rdparty/angle/src/libANGLE/Error.h37
-rw-r--r--src/3rdparty/angle/src/libANGLE/Error.inl66
-rw-r--r--src/3rdparty/angle/src/libANGLE/Fence.cpp46
-rw-r--r--src/3rdparty/angle/src/libANGLE/Fence.h22
-rw-r--r--src/3rdparty/angle/src/libANGLE/Framebuffer.cpp619
-rw-r--r--src/3rdparty/angle/src/libANGLE/Framebuffer.h136
-rw-r--r--src/3rdparty/angle/src/libANGLE/FramebufferAttachment.cpp286
-rw-r--r--src/3rdparty/angle/src/libANGLE/FramebufferAttachment.h238
-rw-r--r--src/3rdparty/angle/src/libANGLE/HandleAllocator.cpp15
-rw-r--r--src/3rdparty/angle/src/libANGLE/HandleAllocator.h2
-rw-r--r--src/3rdparty/angle/src/libANGLE/Image.cpp192
-rw-r--r--src/3rdparty/angle/src/libANGLE/Image.h91
-rw-r--r--src/3rdparty/angle/src/libANGLE/ImageIndex.cpp23
-rw-r--r--src/3rdparty/angle/src/libANGLE/ImageIndex.h8
-rw-r--r--src/3rdparty/angle/src/libANGLE/IndexRangeCache.cpp113
-rw-r--r--src/3rdparty/angle/src/libANGLE/IndexRangeCache.h60
-rw-r--r--src/3rdparty/angle/src/libANGLE/Platform.cpp6
-rw-r--r--src/3rdparty/angle/src/libANGLE/Program.cpp1838
-rw-r--r--src/3rdparty/angle/src/libANGLE/Program.h336
-rw-r--r--src/3rdparty/angle/src/libANGLE/Query.cpp45
-rw-r--r--src/3rdparty/angle/src/libANGLE/Query.h18
-rw-r--r--src/3rdparty/angle/src/libANGLE/RefCountObject.h41
-rw-r--r--src/3rdparty/angle/src/libANGLE/Renderbuffer.cpp78
-rw-r--r--src/3rdparty/angle/src/libANGLE/Renderbuffer.h37
-rw-r--r--src/3rdparty/angle/src/libANGLE/ResourceManager.cpp8
-rw-r--r--src/3rdparty/angle/src/libANGLE/ResourceManager.h11
-rw-r--r--src/3rdparty/angle/src/libANGLE/Sampler.cpp151
-rw-r--r--src/3rdparty/angle/src/libANGLE/Sampler.h88
-rw-r--r--src/3rdparty/angle/src/libANGLE/Shader.cpp279
-rw-r--r--src/3rdparty/angle/src/libANGLE/Shader.h102
-rw-r--r--src/3rdparty/angle/src/libANGLE/State.cpp655
-rw-r--r--src/3rdparty/angle/src/libANGLE/State.h175
-rw-r--r--src/3rdparty/angle/src/libANGLE/Surface.cpp137
-rw-r--r--src/3rdparty/angle/src/libANGLE/Surface.h49
-rw-r--r--src/3rdparty/angle/src/libANGLE/Texture.cpp502
-rw-r--r--src/3rdparty/angle/src/libANGLE/Texture.h198
-rw-r--r--src/3rdparty/angle/src/libANGLE/TransformFeedback.cpp127
-rw-r--r--src/3rdparty/angle/src/libANGLE/TransformFeedback.h44
-rw-r--r--src/3rdparty/angle/src/libANGLE/Uniform.cpp136
-rw-r--r--src/3rdparty/angle/src/libANGLE/Uniform.h65
-rw-r--r--src/3rdparty/angle/src/libANGLE/Version.h33
-rw-r--r--src/3rdparty/angle/src/libANGLE/Version.inl33
-rw-r--r--src/3rdparty/angle/src/libANGLE/VertexArray.cpp115
-rw-r--r--src/3rdparty/angle/src/libANGLE/VertexArray.h83
-rw-r--r--src/3rdparty/angle/src/libANGLE/VertexAttribute.cpp37
-rw-r--r--src/3rdparty/angle/src/libANGLE/VertexAttribute.h73
-rw-r--r--src/3rdparty/angle/src/libANGLE/VertexAttribute.inl103
-rw-r--r--src/3rdparty/angle/src/libANGLE/angletypes.cpp187
-rw-r--r--src/3rdparty/angle/src/libANGLE/angletypes.h181
-rw-r--r--src/3rdparty/angle/src/libANGLE/angletypes.inl78
-rw-r--r--src/3rdparty/angle/src/libANGLE/features.h19
-rw-r--r--src/3rdparty/angle/src/libANGLE/formatutils.cpp978
-rw-r--r--src/3rdparty/angle/src/libANGLE/formatutils.h157
-rw-r--r--src/3rdparty/angle/src/libANGLE/histogram_macros.h107
-rw-r--r--src/3rdparty/angle/src/libANGLE/queryconversions.cpp98
-rw-r--r--src/3rdparty/angle/src/libANGLE/queryconversions.h19
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/BufferImpl.h18
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/BufferImpl_mock.h38
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/CompilerImpl.h4
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/DeviceImpl.cpp22
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/DeviceImpl.h37
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/DisplayImpl.cpp7
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/DisplayImpl.h39
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/FenceNVImpl.h6
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/FenceSyncImpl.h2
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/FramebufferImpl.h34
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/FramebufferImpl_mock.h72
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/ImageImpl.h32
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/ImageImpl_mock.h28
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/ImplFactory.h16
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/IndexRangeCache.cpp114
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/IndexRangeCache.h53
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/ProgramImpl.h90
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/ProgramImpl_mock.h75
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/QueryImpl.h6
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/RenderbufferImpl.h15
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/RenderbufferImpl_mock.h35
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/Renderer.cpp36
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/Renderer.h70
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/SamplerImpl.h25
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/ShaderImpl.h35
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/SurfaceImpl.h10
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/TextureImpl.h27
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/TextureImpl_mock.h43
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/TransformFeedbackImpl.h3
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/TransformFeedbackImpl_mock.h37
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/VertexArrayImpl.h11
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/BufferD3D.cpp194
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/BufferD3D.h43
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/CompilerD3D.cpp122
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/CompilerD3D.h27
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/DeviceD3D.cpp102
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/DeviceD3D.h39
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/DisplayD3D.cpp195
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/DisplayD3D.h39
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/DynamicHLSL.cpp1554
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/DynamicHLSL.h89
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/EGLImageD3D.cpp132
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/EGLImageD3D.h56
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/FramebufferD3D.cpp271
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/FramebufferD3D.h66
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/HLSLCompiler.cpp163
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/HLSLCompiler.h8
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/ImageD3D.cpp21
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/ImageD3D.h12
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexBuffer.h1
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexDataManager.cpp373
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexDataManager.h29
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/ProgramD3D.cpp2357
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/ProgramD3D.h360
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/RenderTargetD3D.h3
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/RenderbufferD3D.cpp54
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/RenderbufferD3D.h18
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/RendererD3D.cpp421
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/RendererD3D.h231
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/SamplerD3D.h25
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/ShaderD3D.cpp347
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/ShaderD3D.h50
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/SurfaceD3D.cpp187
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/SurfaceD3D.h35
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/SwapChainD3D.h7
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureD3D.cpp458
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureD3D.h59
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureStorage.h15
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/TransformFeedbackD3D.cpp8
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/TransformFeedbackD3D.h11
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/VaryingPacking.cpp397
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/VaryingPacking.h175
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexBuffer.cpp71
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexBuffer.h36
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexDataManager.cpp374
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexDataManager.h57
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/WorkaroundsD3D.h66
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Blit11.cpp926
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Blit11.h145
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Buffer11.cpp875
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Buffer11.h52
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Clear11.cpp229
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Clear11.h39
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/DebugAnnotator11.cpp83
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/DebugAnnotator11.h4
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Fence11.cpp22
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Fence11.h18
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Framebuffer11.cpp294
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Framebuffer11.h15
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Image11.cpp336
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Image11.h17
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/IndexBuffer11.cpp17
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/IndexBuffer11.h2
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/InputLayoutCache.cpp693
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/InputLayoutCache.h104
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/NativeWindow.h17
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/PixelTransfer11.cpp31
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Query11.cpp164
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Query11.h13
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/RenderStateCache.cpp116
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/RenderStateCache.h5
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/RenderTarget11.cpp14
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/RenderTarget11.h5
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp3096
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Renderer11.h285
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/ShaderExecutable11.cpp14
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/ShaderExecutable11.h4
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/StateManager11.cpp1040
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/StateManager11.h181
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/SwapChain11.cpp446
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/SwapChain11.h35
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/TextureStorage11.cpp724
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/TextureStorage11.h74
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Trim11.h2
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/VertexArray11.h15
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/VertexBuffer11.cpp69
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/VertexBuffer11.h11
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/copyvertex.inl6
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/dxgi_support_data.json1164
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/dxgi_support_table.cpp1846
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/dxgi_support_table.h44
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/formatutils11.cpp1501
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/formatutils11.h44
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/gen_load_functions_table.cpp0
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/internal_format_initializer_table.cpp170
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/internal_format_initializer_table.h31
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/load_functions_data.json1116
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/load_functions_table.h31
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/load_functions_table_autogen.cpp2098
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.cpp744
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.h276
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/swizzle_format_data.json77
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/swizzle_format_info.h51
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/swizzle_format_info_autogen.cpp203
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/texture_format_data.json692
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/texture_format_table.h64
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/texture_format_table_autogen.cpp1791
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/win32/NativeWindow.cpp156
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.cpp75
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.h64
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.cpp160
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.h71
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow.cpp232
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow.h21
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Blit9.cpp24
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Buffer9.cpp31
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Buffer9.h10
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/DebugAnnotator9.cpp8
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/DebugAnnotator9.h4
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Fence9.cpp44
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Fence9.h10
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Framebuffer9.cpp78
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Framebuffer9.h16
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Image9.cpp89
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Image9.h13
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/IndexBuffer9.cpp6
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/IndexBuffer9.h2
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Query9.cpp36
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Query9.h11
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/RenderTarget9.cpp43
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/RenderTarget9.h26
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp1067
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Renderer9.h203
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/ShaderExecutable9.cpp6
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/ShaderExecutable9.h2
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/StateManager9.cpp903
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/StateManager9.h206
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/SwapChain9.cpp43
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/SwapChain9.h12
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/TextureStorage9.cpp272
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/TextureStorage9.h44
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexArray9.h13
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexBuffer9.cpp58
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexBuffer9.h11
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexDeclarationCache.cpp56
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexDeclarationCache.h6
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/formatutils9.cpp43
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/formatutils9.h10
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/renderer9_utils.cpp108
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/renderer9_utils.h24
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/vertexconversion.h5
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/formatutilsD3D.cpp4
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/imageformats.h168
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimage.cpp105
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimage.h8
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimage_etc.cpp1435
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimage_etc.h140
-rw-r--r--src/3rdparty/angle/src/libANGLE/validationEGL.cpp566
-rw-r--r--src/3rdparty/angle/src/libANGLE/validationEGL.h20
-rw-r--r--src/3rdparty/angle/src/libANGLE/validationES.cpp1377
-rw-r--r--src/3rdparty/angle/src/libANGLE/validationES.h202
-rw-r--r--src/3rdparty/angle/src/libANGLE/validationES2.cpp922
-rw-r--r--src/3rdparty/angle/src/libANGLE/validationES2.h108
-rw-r--r--src/3rdparty/angle/src/libANGLE/validationES3.cpp718
-rw-r--r--src/3rdparty/angle/src/libANGLE/validationES3.h226
-rw-r--r--src/3rdparty/angle/src/libEGL/libEGL.cpp41
-rw-r--r--src/3rdparty/angle/src/libEGL/libEGL.def7
-rw-r--r--src/3rdparty/angle/src/libEGL/libEGL_mingw32.def7
-rw-r--r--src/3rdparty/angle/src/libEGL/libEGLd.def7
-rw-r--r--src/3rdparty/angle/src/libEGL/libEGLd_mingw32.def7
-rw-r--r--src/3rdparty/angle/src/libGLESv2/entry_points_egl.cpp687
-rw-r--r--src/3rdparty/angle/src/libGLESv2/entry_points_egl_ext.cpp457
-rw-r--r--src/3rdparty/angle/src/libGLESv2/entry_points_egl_ext.h18
-rw-r--r--src/3rdparty/angle/src/libGLESv2/entry_points_gles_2_0.cpp715
-rw-r--r--src/3rdparty/angle/src/libGLESv2/entry_points_gles_2_0_ext.cpp936
-rw-r--r--src/3rdparty/angle/src/libGLESv2/entry_points_gles_2_0_ext.h67
-rw-r--r--src/3rdparty/angle/src/libGLESv2/entry_points_gles_3_0.cpp641
-rw-r--r--src/3rdparty/angle/src/libGLESv2/global_state.cpp15
-rw-r--r--src/3rdparty/angle/src/libGLESv2/libGLESv2.cpp154
-rw-r--r--src/3rdparty/angle/src/libGLESv2/libGLESv2.def31
-rw-r--r--src/3rdparty/angle/src/libGLESv2/libGLESv2_mingw32.def32
-rw-r--r--src/3rdparty/angle/src/libGLESv2/libGLESv2d.def31
-rw-r--r--src/3rdparty/angle/src/libGLESv2/libGLESv2d_mingw32.def32
-rw-r--r--src/3rdparty/angle/src/third_party/compiler/ArrayBoundsClamper.cpp5
-rw-r--r--src/3rdparty/angle/src/third_party/murmurhash/MurmurHash3.cpp71
-rw-r--r--src/3rdparty/angle/src/third_party/murmurhash/MurmurHash3.h14
-rw-r--r--src/3rdparty/angle/src/third_party/systeminfo/SystemInfo.cpp2
-rw-r--r--src/3rdparty/angle/src/third_party/trace_event/trace_event.h53
457 files changed, 60625 insertions, 19075 deletions
diff --git a/src/3rdparty/angle/src/common/BitSetIterator.h b/src/3rdparty/angle/src/common/BitSetIterator.h
new file mode 100644
index 0000000000..3248ce44c9
--- /dev/null
+++ b/src/3rdparty/angle/src/common/BitSetIterator.h
@@ -0,0 +1,156 @@
+//
+// Copyright 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.
+//
+// BitSetIterator:
+// A helper class to quickly bitscan bitsets for set bits.
+//
+
+#ifndef COMMON_BITSETITERATOR_H_
+#define COMMON_BITSETITERATOR_H_
+
+#include <stdint.h>
+
+#include <bitset>
+
+#include "common/angleutils.h"
+#include "common/debug.h"
+#include "common/mathutil.h"
+#include "common/platform.h"
+
+namespace angle
+{
+template <size_t N>
+class BitSetIterator final
+{
+ public:
+ BitSetIterator(const std::bitset<N> &bitset);
+ BitSetIterator(const BitSetIterator &other);
+ BitSetIterator &operator=(const BitSetIterator &other);
+
+ class Iterator final
+ {
+ public:
+ Iterator(const std::bitset<N> &bits);
+ Iterator &operator++();
+
+ bool operator==(const Iterator &other) const;
+ bool operator!=(const Iterator &other) const;
+ unsigned long operator*() const { return mCurrentBit; }
+
+ private:
+ unsigned long getNextBit();
+
+ static const size_t BitsPerWord = sizeof(unsigned long) * 8;
+ std::bitset<N> mBits;
+ unsigned long mCurrentBit;
+ unsigned long mOffset;
+ };
+
+ Iterator begin() const { return Iterator(mBits); }
+ Iterator end() const { return Iterator(std::bitset<N>(0)); }
+
+ private:
+ const std::bitset<N> mBits;
+};
+
+template <size_t N>
+BitSetIterator<N>::BitSetIterator(const std::bitset<N> &bitset)
+ : mBits(bitset)
+{
+}
+
+template <size_t N>
+BitSetIterator<N>::BitSetIterator(const BitSetIterator &other)
+ : mBits(other.mBits)
+{
+}
+
+template <size_t N>
+BitSetIterator<N> &BitSetIterator<N>::operator=(const BitSetIterator &other)
+{
+ mBits = other.mBits;
+ return *this;
+}
+
+template <size_t N>
+BitSetIterator<N>::Iterator::Iterator(const std::bitset<N> &bits)
+ : mBits(bits), mCurrentBit(0), mOffset(0)
+{
+ if (bits.any())
+ {
+ mCurrentBit = getNextBit();
+ }
+ else
+ {
+ mOffset = static_cast<unsigned long>(rx::roundUp(N, BitsPerWord));
+ }
+}
+
+template <size_t N>
+typename BitSetIterator<N>::Iterator &BitSetIterator<N>::Iterator::operator++()
+{
+ ASSERT(mBits.any());
+ mBits.set(mCurrentBit - mOffset, 0);
+ mCurrentBit = getNextBit();
+ return *this;
+}
+
+inline unsigned long ScanForward(unsigned long bits)
+{
+ ASSERT(bits != 0);
+#if defined(ANGLE_PLATFORM_WINDOWS)
+ unsigned long firstBitIndex = 0ul;
+ unsigned char ret = _BitScanForward(&firstBitIndex, bits);
+ ASSERT(ret != 0);
+ UNUSED_ASSERTION_VARIABLE(ret);
+ return firstBitIndex;
+#elif defined(ANGLE_PLATFORM_POSIX)
+ return static_cast<unsigned long>(__builtin_ctzl(bits));
+#else
+#error Please implement bit-scan-forward for your platform!
+#endif
+}
+
+template <size_t N>
+bool BitSetIterator<N>::Iterator::operator==(const Iterator &other) const
+{
+ return mOffset == other.mOffset && mBits == other.mBits;
+}
+
+template <size_t N>
+bool BitSetIterator<N>::Iterator::operator!=(const Iterator &other) const
+{
+ return !(*this == other);
+}
+
+template <size_t N>
+unsigned long BitSetIterator<N>::Iterator::getNextBit()
+{
+ static std::bitset<N> wordMask(std::numeric_limits<unsigned long>::max());
+
+ while (mOffset < N)
+ {
+ unsigned long wordBits = (mBits & wordMask).to_ulong();
+ if (wordBits != 0ul)
+ {
+ return ScanForward(wordBits) + mOffset;
+ }
+
+ mBits >>= BitsPerWord;
+ mOffset += BitsPerWord;
+ }
+ return 0;
+}
+
+// Helper to avoid needing to specify the template parameter size
+template <size_t N>
+BitSetIterator<N> IterateBitSet(const std::bitset<N> &bitset)
+{
+ return BitSetIterator<N>(bitset);
+}
+
+} // angle
+
+#endif // COMMON_BITSETITERATOR_H_
diff --git a/src/3rdparty/angle/src/libANGLE/Float16ToFloat32.cpp b/src/3rdparty/angle/src/common/Float16ToFloat32.cpp
index 5bf7b3fce8..acd0d88b60 100644
--- a/src/3rdparty/angle/src/libANGLE/Float16ToFloat32.cpp
+++ b/src/3rdparty/angle/src/common/Float16ToFloat32.cpp
@@ -6,6 +6,8 @@
// This file is automatically generated.
+#include "common/mathutil.h"
+
namespace gl
{
@@ -2197,7 +2199,7 @@ const static unsigned g_offset[64] = {
float float16ToFloat32(unsigned short h)
{
unsigned i32 = g_mantissa[g_offset[h >> 10] + (h & 0x3ff)] + g_exponent[h >> 10];
- return *(float*) &i32;
+ return bitCast<float>(i32);
}
}
diff --git a/src/3rdparty/angle/src/common/Optional.h b/src/3rdparty/angle/src/common/Optional.h
index 9665b7ddf6..256f38f329 100644
--- a/src/3rdparty/angle/src/common/Optional.h
+++ b/src/3rdparty/angle/src/common/Optional.h
@@ -35,11 +35,27 @@ struct Optional
return *this;
}
- static Optional None()
+ Optional &operator=(const T &value)
{
- return Optional();
+ mValue = value;
+ mValid = true;
+ return *this;
+ }
+
+ Optional &operator=(T &&value)
+ {
+ mValue = std::move(value);
+ mValid = true;
+ return *this;
}
+ void reset()
+ {
+ mValid = false;
+ }
+
+ static Optional Invalid() { return Optional(); }
+
bool valid() const { return mValid; }
const T &value() const { return mValue; }
diff --git a/src/3rdparty/angle/src/common/angleutils.cpp b/src/3rdparty/angle/src/common/angleutils.cpp
index af5eb6c447..7099c21730 100644
--- a/src/3rdparty/angle/src/common/angleutils.cpp
+++ b/src/3rdparty/angle/src/common/angleutils.cpp
@@ -8,8 +8,15 @@
#include "common/debug.h"
#include <stdio.h>
+
+#include <limits>
#include <vector>
+namespace angle
+{
+const uintptr_t DirtyPointer = std::numeric_limits<uintptr_t>::max();
+}
+
size_t FormatStringIntoVector(const char *fmt, va_list vararg, std::vector<char>& outBuffer)
{
// Attempt to just print to the current buffer
diff --git a/src/3rdparty/angle/src/common/angleutils.h b/src/3rdparty/angle/src/common/angleutils.h
index 4cf84a3182..a0178fd414 100644
--- a/src/3rdparty/angle/src/common/angleutils.h
+++ b/src/3rdparty/angle/src/common/angleutils.h
@@ -25,16 +25,15 @@ namespace angle
class NonCopyable
{
-#if !defined(_MSC_VER) || (_MSC_VER >= 1800)
public:
NonCopyable() = default;
~NonCopyable() = default;
protected:
NonCopyable(const NonCopyable&) = delete;
void operator=(const NonCopyable&) = delete;
-#endif
};
+extern const uintptr_t DirtyPointer;
}
template <typename T, size_t N>
@@ -72,9 +71,9 @@ void SafeDelete(T*& resource)
template <typename T>
void SafeDeleteContainer(T& resource)
{
- for (typename T::iterator i = resource.begin(); i != resource.end(); i++)
+ for (auto &element : resource)
{
- SafeDelete(*i);
+ SafeDelete(element);
}
resource.clear();
}
diff --git a/src/3rdparty/angle/src/common/debug.cpp b/src/3rdparty/angle/src/common/debug.cpp
index 2fc0a2984a..1fcc062908 100644
--- a/src/3rdparty/angle/src/common/debug.cpp
+++ b/src/3rdparty/angle/src/common/debug.cpp
@@ -44,16 +44,16 @@ void output(bool traceInDebugOnly, MessageType messageType, DebugTraceOutputType
case DebugTraceOutputTypeNone:
break;
case DebugTraceOutputTypeBeginEvent:
- g_debugAnnotator->beginEvent(formattedWideMessage);
+ g_debugAnnotator->beginEvent(formattedWideMessage.c_str());
break;
case DebugTraceOutputTypeSetMarker:
- g_debugAnnotator->setMarker(formattedWideMessage);
+ g_debugAnnotator->setMarker(formattedWideMessage.c_str());
break;
}
}
std::string formattedMessage;
- UNUSED_TRACE_VARIABLE(formattedMessage);
+ UNUSED_VARIABLE(formattedMessage);
#if !defined(NDEBUG) && defined(_MSC_VER)
if (messageType == MESSAGE_ERR)
diff --git a/src/3rdparty/angle/src/common/debug.h b/src/3rdparty/angle/src/common/debug.h
index c4f118ebae..64cfef4cd9 100644
--- a/src/3rdparty/angle/src/common/debug.h
+++ b/src/3rdparty/angle/src/common/debug.h
@@ -16,7 +16,7 @@
#include "common/angleutils.h"
#if !defined(TRACE_OUTPUT_FILE)
-#define TRACE_OUTPUT_FILE "debug.txt"
+#define TRACE_OUTPUT_FILE "angle_debug.txt"
#endif
namespace gl
@@ -47,9 +47,9 @@ class DebugAnnotator : angle::NonCopyable
public:
DebugAnnotator() { };
virtual ~DebugAnnotator() { };
- virtual void beginEvent(const std::wstring &eventName) = 0;
+ virtual void beginEvent(const wchar_t *eventName) = 0;
virtual void endEvent() = 0;
- virtual void setMarker(const std::wstring &markerName) = 0;
+ virtual void setMarker(const wchar_t *markerName) = 0;
virtual bool getStatus() = 0;
};
@@ -63,6 +63,8 @@ bool DebugAnnotationsActive();
#define ANGLE_TRACE_ENABLED
#endif
+#define ANGLE_EMPTY_STATEMENT for (;;) break
+
// A macro to output a trace of a function call and its arguments to the debugging log
#if defined(ANGLE_TRACE_ENABLED)
#define TRACE(message, ...) gl::trace(true, gl::MESSAGE_TRACE, "trace: %s(%d): " message "\n", __FUNCTION__, __LINE__, ##__VA_ARGS__)
@@ -89,7 +91,7 @@ bool DebugAnnotationsActive();
#if defined(_MSC_VER)
#define EVENT(message, ...) gl::ScopedPerfEventHelper scopedPerfEventHelper ## __LINE__("%s" message "\n", __FUNCTION__, __VA_ARGS__);
#else
-#define EVENT(message, ...) gl::ScopedPerfEventHelper scopedPerfEventHelper(message "\n", ##__VA_ARGS__);
+#define EVENT(message, ...) gl::ScopedPerfEventHelper scopedPerfEventHelper("%s" message "\n", __FUNCTION__, ##__VA_ARGS__);
#endif // _MSC_VER
#else
#define EVENT(message, ...) (void(0))
@@ -101,22 +103,18 @@ bool DebugAnnotationsActive();
// A macro asserting a condition and outputting failures to the debug log
#if !defined(NDEBUG)
-#define ASSERT(expression) do { \
+#define ASSERT(expression) { \
if(!(expression)) \
- ERR("\t! Assert failed in %s(%d): "#expression"\n", __FUNCTION__, __LINE__); \
+ ERR("\t! Assert failed in %s(%d): %s\n", __FUNCTION__, __LINE__, #expression); \
assert(expression); \
- } while(0)
+ } ANGLE_EMPTY_STATEMENT
#define UNUSED_ASSERTION_VARIABLE(variable)
#else
#define ASSERT(expression) (void(0))
#define UNUSED_ASSERTION_VARIABLE(variable) ((void)variable)
#endif
-#ifndef ANGLE_ENABLE_DEBUG_TRACE
-#define UNUSED_TRACE_VARIABLE(variable) ((void)variable)
-#else
-#define UNUSED_TRACE_VARIABLE(variable)
-#endif
+#define UNUSED_VARIABLE(variable) ((void)variable)
// A macro to indicate unimplemented functionality
@@ -131,29 +129,22 @@ bool DebugAnnotationsActive();
#endif
#if !defined(NDEBUG)
-#define UNIMPLEMENTED() do { \
+#define UNIMPLEMENTED() { \
FIXME("\t! Unimplemented: %s(%d)\n", __FUNCTION__, __LINE__); \
assert(NOASSERT_UNIMPLEMENTED); \
- } while(0)
+ } ANGLE_EMPTY_STATEMENT
#else
#define UNIMPLEMENTED() FIXME("\t! Unimplemented: %s(%d)\n", __FUNCTION__, __LINE__)
#endif
// A macro for code which is not expected to be reached under valid assumptions
#if !defined(NDEBUG)
-#define UNREACHABLE() do { \
+#define UNREACHABLE() { \
ERR("\t! Unreachable reached: %s(%d)\n", __FUNCTION__, __LINE__); \
assert(false); \
- } while(0)
+ } ANGLE_EMPTY_STATEMENT
#else
#define UNREACHABLE() ERR("\t! Unreachable reached: %s(%d)\n", __FUNCTION__, __LINE__)
#endif
-// A macro that determines whether an object has a given runtime type.
-#if !defined(NDEBUG) && (!defined(_MSC_VER) || defined(_CPPRTTI)) && (!defined(__GNUC__) || __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 3) || defined(__GXX_RTTI))
-#define HAS_DYNAMIC_TYPE(type, obj) (dynamic_cast<type >(obj) != NULL)
-#else
-#define HAS_DYNAMIC_TYPE(type, obj) true
-#endif
-
#endif // COMMON_DEBUG_H_
diff --git a/src/3rdparty/angle/src/common/event_tracer.cpp b/src/3rdparty/angle/src/common/event_tracer.cpp
index eb0c98c9e5..c9eb5e3073 100644
--- a/src/3rdparty/angle/src/common/event_tracer.cpp
+++ b/src/3rdparty/angle/src/common/event_tracer.cpp
@@ -4,35 +4,53 @@
#include "common/event_tracer.h"
-namespace gl
-{
-
-GetCategoryEnabledFlagFunc g_getCategoryEnabledFlag;
-AddTraceEventFunc g_addTraceEvent;
+#include "common/debug.h"
-} // namespace gl
-
-namespace gl
+namespace angle
{
-const unsigned char* TraceGetTraceCategoryEnabledFlag(const char* name)
+const unsigned char *GetTraceCategoryEnabledFlag(const char *name)
{
- if (g_getCategoryEnabledFlag)
+ angle::Platform *platform = ANGLEPlatformCurrent();
+ ASSERT(platform);
+
+ const unsigned char *categoryEnabledFlag = platform->getTraceCategoryEnabledFlag(name);
+ if (categoryEnabledFlag != nullptr)
{
- return g_getCategoryEnabledFlag(name);
+ return categoryEnabledFlag;
}
+
static unsigned char disabled = 0;
return &disabled;
}
-void TraceAddTraceEvent(char phase, const unsigned char* categoryGroupEnabled, const char* name, unsigned long long id,
- int numArgs, const char** argNames, const unsigned char* argTypes,
- const unsigned long long* argValues, unsigned char flags)
+Platform::TraceEventHandle AddTraceEvent(char phase, const unsigned char* categoryGroupEnabled, const char* name, unsigned long long id,
+ int numArgs, const char** argNames, const unsigned char* argTypes,
+ const unsigned long long* argValues, unsigned char flags)
{
- if (g_addTraceEvent)
+ angle::Platform *platform = ANGLEPlatformCurrent();
+ ASSERT(platform);
+
+ double timestamp = platform->monotonicallyIncreasingTime();
+
+ if (timestamp != 0)
{
- g_addTraceEvent(phase, categoryGroupEnabled, name, id, numArgs, argNames, argTypes, argValues, flags);
+ angle::Platform::TraceEventHandle handle =
+ platform->addTraceEvent(phase,
+ categoryGroupEnabled,
+ name,
+ id,
+ timestamp,
+ numArgs,
+ argNames,
+ argTypes,
+ argValues,
+ flags);
+ ASSERT(handle != 0);
+ return handle;
}
+
+ return static_cast<Platform::TraceEventHandle>(0);
}
-} // namespace gl
+} // namespace angle
diff --git a/src/3rdparty/angle/src/common/event_tracer.h b/src/3rdparty/angle/src/common/event_tracer.h
index dbe4c1bef9..ed70f249d2 100644
--- a/src/3rdparty/angle/src/common/event_tracer.h
+++ b/src/3rdparty/angle/src/common/event_tracer.h
@@ -6,28 +6,16 @@
#define COMMON_EVENT_TRACER_H_
#include "common/platform.h"
+#include "platform/Platform.h"
-extern "C" {
-
-typedef const unsigned char* (*GetCategoryEnabledFlagFunc)(const char* name);
-typedef void (*AddTraceEventFunc)(char phase, const unsigned char* categoryGroupEnabled, const char* name,
- unsigned long long id, int numArgs, const char** argNames,
- const unsigned char* argTypes, const unsigned long long* argValues,
- unsigned char flags);
-
-}
-
-namespace gl
+namespace angle
{
-extern GetCategoryEnabledFlagFunc g_getCategoryEnabledFlag;
-extern AddTraceEventFunc g_addTraceEvent;
-
-const unsigned char* TraceGetTraceCategoryEnabledFlag(const char* name);
-
-void TraceAddTraceEvent(char phase, const unsigned char* categoryGroupEnabled, const char* name, unsigned long long id,
- int numArgs, const char** argNames, const unsigned char* argTypes,
- const unsigned long long* argValues, unsigned char flags);
+const unsigned char *GetTraceCategoryEnabledFlag(const char* name);
+Platform::TraceEventHandle AddTraceEvent(char phase, const unsigned char* categoryGroupEnabled, const char* name,
+ unsigned long long id, int numArgs, const char** argNames,
+ const unsigned char* argTypes, const unsigned long long* argValues,
+ unsigned char flags);
}
diff --git a/src/3rdparty/angle/src/common/mathutil.cpp b/src/3rdparty/angle/src/common/mathutil.cpp
index 496633632b..927b6ebebe 100644
--- a/src/3rdparty/angle/src/common/mathutil.cpp
+++ b/src/3rdparty/angle/src/common/mathutil.cpp
@@ -43,16 +43,16 @@ unsigned int convertRGBFloatsTo999E5(float red, float green, float blue)
const float max_c = std::max<float>(std::max<float>(red_c, green_c), blue_c);
const float exp_p = std::max<float>(-g_sharedexp_bias - 1, floor(log(max_c))) + 1 + g_sharedexp_bias;
- const int max_s = floor((max_c / (pow(2.0f, exp_p - g_sharedexp_bias - g_sharedexp_mantissabits))) + 0.5f);
- const int exp_s = (max_s < pow(2.0f, g_sharedexp_mantissabits)) ? exp_p : exp_p + 1;
+ const int max_s = static_cast<int>(floor((max_c / (pow(2.0f, exp_p - g_sharedexp_bias - g_sharedexp_mantissabits))) + 0.5f));
+ const int exp_s = static_cast<int>((max_s < pow(2.0f, g_sharedexp_mantissabits)) ? exp_p : exp_p + 1);
RGB9E5Data output;
- output.R = floor((red_c / (pow(2.0f, exp_s - g_sharedexp_bias - g_sharedexp_mantissabits))) + 0.5f);
- output.G = floor((green_c / (pow(2.0f, exp_s - g_sharedexp_bias - g_sharedexp_mantissabits))) + 0.5f);
- output.B = floor((blue_c / (pow(2.0f, exp_s - g_sharedexp_bias - g_sharedexp_mantissabits))) + 0.5f);
+ output.R = static_cast<unsigned int>(floor((red_c / (pow(2.0f, exp_s - g_sharedexp_bias - g_sharedexp_mantissabits))) + 0.5f));
+ output.G = static_cast<unsigned int>(floor((green_c / (pow(2.0f, exp_s - g_sharedexp_bias - g_sharedexp_mantissabits))) + 0.5f));
+ output.B = static_cast<unsigned int>(floor((blue_c / (pow(2.0f, exp_s - g_sharedexp_bias - g_sharedexp_mantissabits))) + 0.5f));
output.E = exp_s;
- return *reinterpret_cast<unsigned int*>(&output);
+ return bitCast<unsigned int>(output);
}
void convert999E5toRGBFloats(unsigned int input, float *red, float *green, float *blue)
diff --git a/src/3rdparty/angle/src/common/mathutil.h b/src/3rdparty/angle/src/common/mathutil.h
index 1015bd2312..3de62aef10 100644
--- a/src/3rdparty/angle/src/common/mathutil.h
+++ b/src/3rdparty/angle/src/common/mathutil.h
@@ -14,7 +14,9 @@
#include <limits>
#include <algorithm>
+#include <math.h>
#include <string.h>
+#include <stdint.h>
#include <stdlib.h>
namespace gl
@@ -67,14 +69,29 @@ inline int clampToInt(unsigned int x)
template <typename DestT, typename SrcT>
inline DestT clampCast(SrcT value)
{
- // This assumes SrcT can properly represent DestT::min/max
- // Unfortunately we can't use META_ASSERT without C++11 constexpr support
- ASSERT(static_cast<DestT>(static_cast<SrcT>(std::numeric_limits<DestT>::min())) == std::numeric_limits<DestT>::min());
- ASSERT(static_cast<DestT>(static_cast<SrcT>(std::numeric_limits<DestT>::max())) == std::numeric_limits<DestT>::max());
-
- SrcT lo = static_cast<SrcT>(std::numeric_limits<DestT>::min());
- SrcT hi = static_cast<SrcT>(std::numeric_limits<DestT>::max());
- return static_cast<DestT>(value > lo ? (value > hi ? hi : value) : lo);
+ static const DestT destLo = std::numeric_limits<DestT>::min();
+ static const DestT destHi = std::numeric_limits<DestT>::max();
+ static const SrcT srcLo = static_cast<SrcT>(destLo);
+ static const SrcT srcHi = static_cast<SrcT>(destHi);
+
+ // When value is outside of or equal to the limits for DestT we use the DestT limit directly.
+ // This avoids undefined behaviors due to loss of precision when converting from floats to
+ // integers:
+ // destHi for ints is 2147483647 but the closest float number is around 2147483648, so when
+ // doing a conversion from float to int we run into an UB because the float is outside of the
+ // range representable by the int.
+ if (value <= srcLo)
+ {
+ return destLo;
+ }
+ else if (value >= srcHi)
+ {
+ return destHi;
+ }
+ else
+ {
+ return static_cast<DestT>(value);
+ }
}
template<typename T, typename MIN, typename MAX>
@@ -119,9 +136,6 @@ inline bool supportsSSE2()
return supports;
}
-#if defined(__GNUC__)
- supports = __builtin_cpu_supports("sse2");
-#else
int info[4];
__cpuid(info, 0);
@@ -131,7 +145,6 @@ inline bool supportsSSE2()
supports = (info[3] >> 26) & 1;
}
-#endif
checked = true;
@@ -153,13 +166,13 @@ destType bitCast(const sourceType &source)
inline unsigned short float32ToFloat16(float fp32)
{
- unsigned int fp32i = (unsigned int&)fp32;
+ unsigned int fp32i = bitCast<unsigned int>(fp32);
unsigned int sign = (fp32i & 0x80000000) >> 16;
unsigned int abs = fp32i & 0x7FFFFFFF;
if(abs > 0x47FFEFFF) // Infinity
{
- return sign | 0x7FFF;
+ return static_cast<unsigned short>(sign | 0x7FFF);
}
else if(abs < 0x38800000) // Denormal
{
@@ -175,11 +188,11 @@ inline unsigned short float32ToFloat16(float fp32)
abs = 0;
}
- return sign | (abs + 0x00000FFF + ((abs >> 13) & 1)) >> 13;
+ return static_cast<unsigned short>(sign | (abs + 0x00000FFF + ((abs >> 13) & 1)) >> 13);
}
else
{
- return sign | (abs + 0xC8000000 + 0x00000FFF + ((abs >> 13) & 1)) >> 13;
+ return static_cast<unsigned short>(sign | (abs + 0xC8000000 + 0x00000FFF + ((abs >> 13) & 1)) >> 13);
}
}
@@ -426,14 +439,14 @@ inline float normalizedToFloat(T input)
template <typename T>
inline T floatToNormalized(float input)
{
- return std::numeric_limits<T>::max() * input + 0.5f;
+ return static_cast<T>(std::numeric_limits<T>::max() * input + 0.5f);
}
template <unsigned int outputBitCount, typename T>
inline T floatToNormalized(float input)
{
static_assert(outputBitCount < (sizeof(T) * 8), "T must have more bits than outputBitCount.");
- return ((1 << outputBitCount) - 1) * input + 0.5f;
+ return static_cast<T>(((1 << outputBitCount) - 1) * input + 0.5f);
}
template <unsigned int inputBitCount, unsigned int inputBitStart, typename T>
@@ -480,9 +493,10 @@ inline unsigned int average(unsigned int a, unsigned int b)
return ((a ^ b) >> 1) + (a & b);
}
-inline signed int average(signed int a, signed int b)
+inline int average(int a, int b)
{
- return ((long long)a + (long long)b) / 2;
+ long long average = (static_cast<long long>(a) + static_cast<long long>(b)) / 2ll;
+ return static_cast<int>(average);
}
inline float average(float a, float b)
@@ -497,20 +511,14 @@ inline unsigned short averageHalfFloat(unsigned short a, unsigned short b)
inline unsigned int averageFloat11(unsigned int a, unsigned int b)
{
- return float32ToFloat11((float11ToFloat32(a) + float11ToFloat32(b)) * 0.5f);
+ return float32ToFloat11((float11ToFloat32(static_cast<unsigned short>(a)) + float11ToFloat32(static_cast<unsigned short>(b))) * 0.5f);
}
inline unsigned int averageFloat10(unsigned int a, unsigned int b)
{
- return float32ToFloat10((float10ToFloat32(a) + float10ToFloat32(b)) * 0.5f);
-}
-
+ return float32ToFloat10((float10ToFloat32(static_cast<unsigned short>(a)) + float10ToFloat32(static_cast<unsigned short>(b))) * 0.5f);
}
-namespace rx
-{
-
-// Represents intervals of the type [a, b)
template <typename T>
struct Range
{
@@ -533,11 +541,146 @@ struct Range
return start < other.end;
}
}
+
+ void extend(T value)
+ {
+ start = value > start ? value : start;
+ end = value < end ? value : end;
+ }
+
+ bool empty() const
+ {
+ return end <= start;
+ }
};
typedef Range<int> RangeI;
typedef Range<unsigned int> RangeUI;
+struct IndexRange
+{
+ IndexRange() : IndexRange(0, 0, 0) {}
+ IndexRange(size_t start_, size_t end_, size_t vertexIndexCount_)
+ : start(start_), end(end_), vertexIndexCount(vertexIndexCount_)
+ {
+ ASSERT(start <= end);
+ }
+
+ // Number of vertices in the range.
+ size_t vertexCount() const { return (end - start) + 1; }
+
+ // Inclusive range of indices that are not primitive restart
+ size_t start;
+ size_t end;
+
+ // Number of non-primitive restart indices
+ size_t vertexIndexCount;
+};
+
+// First, both normalized floating-point values are converted into 16-bit integer values.
+// Then, the results are packed into the returned 32-bit unsigned integer.
+// The first float value will be written to the least significant bits of the output;
+// the last float value will be written to the most significant bits.
+// The conversion of each value to fixed point is done as follows :
+// packSnorm2x16 : round(clamp(c, -1, +1) * 32767.0)
+inline uint32_t packSnorm2x16(float f1, float f2)
+{
+ int16_t leastSignificantBits = static_cast<int16_t>(roundf(clamp(f1, -1.0f, 1.0f) * 32767.0f));
+ int16_t mostSignificantBits = static_cast<int16_t>(roundf(clamp(f2, -1.0f, 1.0f) * 32767.0f));
+ return static_cast<uint32_t>(mostSignificantBits) << 16 |
+ (static_cast<uint32_t>(leastSignificantBits) & 0xFFFF);
+}
+
+// First, unpacks a single 32-bit unsigned integer u into a pair of 16-bit unsigned integers. Then, each
+// component is converted to a normalized floating-point value to generate the returned two float values.
+// The first float value will be extracted from the least significant bits of the input;
+// the last float value will be extracted from the most-significant bits.
+// The conversion for unpacked fixed-point value to floating point is done as follows:
+// unpackSnorm2x16 : clamp(f / 32767.0, -1, +1)
+inline void unpackSnorm2x16(uint32_t u, float *f1, float *f2)
+{
+ int16_t leastSignificantBits = static_cast<int16_t>(u & 0xFFFF);
+ int16_t mostSignificantBits = static_cast<int16_t>(u >> 16);
+ *f1 = clamp(static_cast<float>(leastSignificantBits) / 32767.0f, -1.0f, 1.0f);
+ *f2 = clamp(static_cast<float>(mostSignificantBits) / 32767.0f, -1.0f, 1.0f);
+}
+
+// First, both normalized floating-point values are converted into 16-bit integer values.
+// Then, the results are packed into the returned 32-bit unsigned integer.
+// The first float value will be written to the least significant bits of the output;
+// the last float value will be written to the most significant bits.
+// The conversion of each value to fixed point is done as follows:
+// packUnorm2x16 : round(clamp(c, 0, +1) * 65535.0)
+inline uint32_t packUnorm2x16(float f1, float f2)
+{
+ uint16_t leastSignificantBits = static_cast<uint16_t>(roundf(clamp(f1, 0.0f, 1.0f) * 65535.0f));
+ uint16_t mostSignificantBits = static_cast<uint16_t>(roundf(clamp(f2, 0.0f, 1.0f) * 65535.0f));
+ return static_cast<uint32_t>(mostSignificantBits) << 16 | static_cast<uint32_t>(leastSignificantBits);
+}
+
+// First, unpacks a single 32-bit unsigned integer u into a pair of 16-bit unsigned integers. Then, each
+// component is converted to a normalized floating-point value to generate the returned two float values.
+// The first float value will be extracted from the least significant bits of the input;
+// the last float value will be extracted from the most-significant bits.
+// The conversion for unpacked fixed-point value to floating point is done as follows:
+// unpackUnorm2x16 : f / 65535.0
+inline void unpackUnorm2x16(uint32_t u, float *f1, float *f2)
+{
+ uint16_t leastSignificantBits = static_cast<uint16_t>(u & 0xFFFF);
+ uint16_t mostSignificantBits = static_cast<uint16_t>(u >> 16);
+ *f1 = static_cast<float>(leastSignificantBits) / 65535.0f;
+ *f2 = static_cast<float>(mostSignificantBits) / 65535.0f;
+}
+
+// Returns an unsigned integer obtained by converting the two floating-point values to the 16-bit
+// floating-point representation found in the OpenGL ES Specification, and then packing these
+// two 16-bit integers into a 32-bit unsigned integer.
+// f1: The 16 least-significant bits of the result;
+// f2: The 16 most-significant bits.
+inline uint32_t packHalf2x16(float f1, float f2)
+{
+ uint16_t leastSignificantBits = static_cast<uint16_t>(float32ToFloat16(f1));
+ uint16_t mostSignificantBits = static_cast<uint16_t>(float32ToFloat16(f2));
+ return static_cast<uint32_t>(mostSignificantBits) << 16 | static_cast<uint32_t>(leastSignificantBits);
+}
+
+// Returns two floating-point values obtained by unpacking a 32-bit unsigned integer into a pair of 16-bit values,
+// interpreting those values as 16-bit floating-point numbers according to the OpenGL ES Specification,
+// and converting them to 32-bit floating-point values.
+// The first float value is obtained from the 16 least-significant bits of u;
+// the second component is obtained from the 16 most-significant bits of u.
+inline void unpackHalf2x16(uint32_t u, float *f1, float *f2)
+{
+ uint16_t leastSignificantBits = static_cast<uint16_t>(u & 0xFFFF);
+ uint16_t mostSignificantBits = static_cast<uint16_t>(u >> 16);
+
+ *f1 = float16ToFloat32(leastSignificantBits);
+ *f2 = float16ToFloat32(mostSignificantBits);
+}
+
+// Returns whether the argument is Not a Number.
+// IEEE 754 single precision NaN representation: Exponent(8 bits) - 255, Mantissa(23 bits) - non-zero.
+inline bool isNaN(float f)
+{
+ // Exponent mask: ((1u << 8) - 1u) << 23 = 0x7f800000u
+ // Mantissa mask: ((1u << 23) - 1u) = 0x7fffffu
+ return ((bitCast<uint32_t>(f) & 0x7f800000u) == 0x7f800000u) && (bitCast<uint32_t>(f) & 0x7fffffu);
+}
+
+// Returns whether the argument is infinity.
+// IEEE 754 single precision infinity representation: Exponent(8 bits) - 255, Mantissa(23 bits) - zero.
+inline bool isInf(float f)
+{
+ // Exponent mask: ((1u << 8) - 1u) << 23 = 0x7f800000u
+ // Mantissa mask: ((1u << 23) - 1u) = 0x7fffffu
+ return ((bitCast<uint32_t>(f) & 0x7f800000u) == 0x7f800000u) && !(bitCast<uint32_t>(f) & 0x7fffffu);
+}
+
+}
+
+namespace rx
+{
+
template <typename T>
T roundUp(const T value, const T alignment)
{
@@ -573,6 +716,7 @@ inline bool IsIntegerCastSafe(BigIntT bigValue)
#if defined(_MSC_VER)
#define ANGLE_ROTL(x,y) _rotl(x,y)
+#define ANGLE_ROTR16(x,y) _rotr16(x,y)
#else
@@ -581,7 +725,13 @@ inline uint32_t RotL(uint32_t x, int8_t r)
return (x << r) | (x >> (32 - r));
}
+inline uint16_t RotR16(uint16_t x, int8_t r)
+{
+ return (x >> r) | (x << (16 - r));
+}
+
#define ANGLE_ROTL(x,y) RotL(x,y)
+#define ANGLE_ROTR16(x,y) RotR16(x,y)
#endif // namespace rx
diff --git a/src/3rdparty/angle/src/common/matrix_utils.h b/src/3rdparty/angle/src/common/matrix_utils.h
new file mode 100644
index 0000000000..6f3187c3e8
--- /dev/null
+++ b/src/3rdparty/angle/src/common/matrix_utils.h
@@ -0,0 +1,349 @@
+//
+// Copyright 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.
+//
+// Matrix:
+// Utility class implementing various matrix operations.
+// Supports matrices with minimum 2 and maximum 4 number of rows/columns.
+//
+// TODO: Check if we can merge Matrix.h in sample_util with this and replace it with this implementation.
+// TODO: Rename this file to Matrix.h once we remove Matrix.h in sample_util.
+
+#ifndef COMMON_MATRIX_UTILS_H_
+#define COMMON_MATRIX_UTILS_H_
+
+#include <vector>
+
+#include "common/debug.h"
+
+namespace angle
+{
+
+template<typename T>
+class Matrix
+{
+ public:
+ Matrix(const std::vector<T> &elements, const unsigned int &numRows, const unsigned int &numCols)
+ : mElements(elements),
+ mRows(numRows),
+ mCols(numCols)
+ {
+ ASSERT(rows() >= 1 && rows() <= 4);
+ ASSERT(columns() >= 1 && columns() <= 4);
+ }
+
+ Matrix(const std::vector<T> &elements, const unsigned int &size)
+ : mElements(elements),
+ mRows(size),
+ mCols(size)
+ {
+ ASSERT(rows() >= 1 && rows() <= 4);
+ ASSERT(columns() >= 1 && columns() <= 4);
+ }
+
+ Matrix(const T *elements, const unsigned int &size)
+ : mRows(size),
+ mCols(size)
+ {
+ ASSERT(rows() >= 1 && rows() <= 4);
+ ASSERT(columns() >= 1 && columns() <= 4);
+ for (size_t i = 0; i < size * size; i++)
+ mElements.push_back(elements[i]);
+ }
+
+ const T &operator()(const unsigned int &rowIndex, const unsigned int &columnIndex) const
+ {
+ return mElements[rowIndex * columns() + columnIndex];
+ }
+
+ T &operator()(const unsigned int &rowIndex, const unsigned int &columnIndex)
+ {
+ return mElements[rowIndex * columns() + columnIndex];
+ }
+
+ const T &at(const unsigned int &rowIndex, const unsigned int &columnIndex) const
+ {
+ return operator()(rowIndex, columnIndex);
+ }
+
+ Matrix<T> operator*(const Matrix<T> &m)
+ {
+ ASSERT(columns() == m.rows());
+
+ unsigned int resultRows = rows();
+ unsigned int resultCols = m.columns();
+ Matrix<T> result(std::vector<T>(resultRows * resultCols), resultRows, resultCols);
+ for (unsigned int i = 0; i < resultRows; i++)
+ {
+ for (unsigned int j = 0; j < resultCols; j++)
+ {
+ T tmp = 0.0f;
+ for (unsigned int k = 0; k < columns(); k++)
+ tmp += at(i, k) * m(k, j);
+ result(i, j) = tmp;
+ }
+ }
+
+ return result;
+ }
+
+ unsigned int size() const
+ {
+ ASSERT(rows() == columns());
+ return rows();
+ }
+
+ unsigned int rows() const { return mRows; }
+
+ unsigned int columns() const { return mCols; }
+
+ std::vector<T> elements() const { return mElements; }
+
+ Matrix<T> compMult(const Matrix<T> &mat1) const
+ {
+ Matrix result(std::vector<T>(mElements.size()), size());
+ for (unsigned int i = 0; i < columns(); i++)
+ for (unsigned int j = 0; j < rows(); j++)
+ result(i, j) = at(i, j) * mat1(i, j);
+
+ return result;
+ }
+
+ Matrix<T> outerProduct(const Matrix<T> &mat1) const
+ {
+ unsigned int cols = mat1.columns();
+ Matrix result(std::vector<T>(rows() * cols), rows(), cols);
+ for (unsigned int i = 0; i < rows(); i++)
+ for (unsigned int j = 0; j < cols; j++)
+ result(i, j) = at(i, 0) * mat1(0, j);
+
+ return result;
+ }
+
+ Matrix<T> transpose() const
+ {
+ Matrix result(std::vector<T>(mElements.size()), columns(), rows());
+ for (unsigned int i = 0; i < columns(); i++)
+ for (unsigned int j = 0; j < rows(); j++)
+ result(i, j) = at(j, i);
+
+ return result;
+ }
+
+ T determinant() const
+ {
+ ASSERT(rows() == columns());
+
+ switch (size())
+ {
+ case 2:
+ return at(0, 0) * at(1, 1) - at(0, 1) * at(1, 0);
+
+ case 3:
+ return at(0, 0) * at(1, 1) * at(2, 2) +
+ at(0, 1) * at(1, 2) * at(2, 0) +
+ at(0, 2) * at(1, 0) * at(2, 1) -
+ at(0, 2) * at(1, 1) * at(2, 0) -
+ at(0, 1) * at(1, 0) * at(2, 2) -
+ at(0, 0) * at(1, 2) * at(2, 1);
+
+ case 4:
+ {
+ const float minorMatrices[4][3 * 3] =
+ {
+ {
+ at(1, 1), at(2, 1), at(3, 1),
+ at(1, 2), at(2, 2), at(3, 2),
+ at(1, 3), at(2, 3), at(3, 3),
+ },
+ {
+ at(1, 0), at(2, 0), at(3, 0),
+ at(1, 2), at(2, 2), at(3, 2),
+ at(1, 3), at(2, 3), at(3, 3),
+ },
+ {
+ at(1, 0), at(2, 0), at(3, 0),
+ at(1, 1), at(2, 1), at(3, 1),
+ at(1, 3), at(2, 3), at(3, 3),
+ },
+ {
+ at(1, 0), at(2, 0), at(3, 0),
+ at(1, 1), at(2, 1), at(3, 1),
+ at(1, 2), at(2, 2), at(3, 2),
+ }
+ };
+ return at(0, 0) * Matrix<T>(minorMatrices[0], 3).determinant() -
+ at(0, 1) * Matrix<T>(minorMatrices[1], 3).determinant() +
+ at(0, 2) * Matrix<T>(minorMatrices[2], 3).determinant() -
+ at(0, 3) * Matrix<T>(minorMatrices[3], 3).determinant();
+ }
+
+ default:
+ UNREACHABLE();
+ break;
+ }
+
+ return T();
+ }
+
+ Matrix<T> inverse() const
+ {
+ ASSERT(rows() == columns());
+
+ Matrix<T> cof(std::vector<T>(mElements.size()), rows(), columns());
+ switch (size())
+ {
+ case 2:
+ cof(0, 0) = at(1, 1);
+ cof(0, 1) = -at(1, 0);
+ cof(1, 0) = -at(0, 1);
+ cof(1, 1) = at(0, 0);
+ break;
+
+ case 3:
+ cof(0, 0) = at(1, 1) * at(2, 2) -
+ at(2, 1) * at(1, 2);
+ cof(0, 1) = -(at(1, 0) * at(2, 2) -
+ at(2, 0) * at(1, 2));
+ cof(0, 2) = at(1, 0) * at(2, 1) -
+ at(2, 0) * at(1, 1);
+ cof(1, 0) = -(at(0, 1) * at(2, 2) -
+ at(2, 1) * at(0, 2));
+ cof(1, 1) = at(0, 0) * at(2, 2) -
+ at(2, 0) * at(0, 2);
+ cof(1, 2) = -(at(0, 0) * at(2, 1) -
+ at(2, 0) * at(0, 1));
+ cof(2, 0) = at(0, 1) * at(1, 2) -
+ at(1, 1) * at(0, 2);
+ cof(2, 1) = -(at(0, 0) * at(1, 2) -
+ at(1, 0) * at(0, 2));
+ cof(2, 2) = at(0, 0) * at(1, 1) -
+ at(1, 0) * at(0, 1);
+ break;
+
+ case 4:
+ cof(0, 0) = at(1, 1) * at(2, 2) * at(3, 3) +
+ at(2, 1) * at(3, 2) * at(1, 3) +
+ at(3, 1) * at(1, 2) * at(2, 3) -
+ at(1, 1) * at(3, 2) * at(2, 3) -
+ at(2, 1) * at(1, 2) * at(3, 3) -
+ at(3, 1) * at(2, 2) * at(1, 3);
+ cof(0, 1) = -(at(1, 0) * at(2, 2) * at(3, 3) +
+ at(2, 0) * at(3, 2) * at(1, 3) +
+ at(3, 0) * at(1, 2) * at(2, 3) -
+ at(1, 0) * at(3, 2) * at(2, 3) -
+ at(2, 0) * at(1, 2) * at(3, 3) -
+ at(3, 0) * at(2, 2) * at(1, 3));
+ cof(0, 2) = at(1, 0) * at(2, 1) * at(3, 3) +
+ at(2, 0) * at(3, 1) * at(1, 3) +
+ at(3, 0) * at(1, 1) * at(2, 3) -
+ at(1, 0) * at(3, 1) * at(2, 3) -
+ at(2, 0) * at(1, 1) * at(3, 3) -
+ at(3, 0) * at(2, 1) * at(1, 3);
+ cof(0, 3) = -(at(1, 0) * at(2, 1) * at(3, 2) +
+ at(2, 0) * at(3, 1) * at(1, 2) +
+ at(3, 0) * at(1, 1) * at(2, 2) -
+ at(1, 0) * at(3, 1) * at(2, 2) -
+ at(2, 0) * at(1, 1) * at(3, 2) -
+ at(3, 0) * at(2, 1) * at(1, 2));
+ cof(1, 0) = -(at(0, 1) * at(2, 2) * at(3, 3) +
+ at(2, 1) * at(3, 2) * at(0, 3) +
+ at(3, 1) * at(0, 2) * at(2, 3) -
+ at(0, 1) * at(3, 2) * at(2, 3) -
+ at(2, 1) * at(0, 2) * at(3, 3) -
+ at(3, 1) * at(2, 2) * at(0, 3));
+ cof(1, 1) = at(0, 0) * at(2, 2) * at(3, 3) +
+ at(2, 0) * at(3, 2) * at(0, 3) +
+ at(3, 0) * at(0, 2) * at(2, 3) -
+ at(0, 0) * at(3, 2) * at(2, 3) -
+ at(2, 0) * at(0, 2) * at(3, 3) -
+ at(3, 0) * at(2, 2) * at(0, 3);
+ cof(1, 2) = -(at(0, 0) * at(2, 1) * at(3, 3) +
+ at(2, 0) * at(3, 1) * at(0, 3) +
+ at(3, 0) * at(0, 1) * at(2, 3) -
+ at(0, 0) * at(3, 1) * at(2, 3) -
+ at(2, 0) * at(0, 1) * at(3, 3) -
+ at(3, 0) * at(2, 1) * at(0, 3));
+ cof(1, 3) = at(0, 0) * at(2, 1) * at(3, 2) +
+ at(2, 0) * at(3, 1) * at(0, 2) +
+ at(3, 0) * at(0, 1) * at(2, 2) -
+ at(0, 0) * at(3, 1) * at(2, 2) -
+ at(2, 0) * at(0, 1) * at(3, 2) -
+ at(3, 0) * at(2, 1) * at(0, 2);
+ cof(2, 0) = at(0, 1) * at(1, 2) * at(3, 3) +
+ at(1, 1) * at(3, 2) * at(0, 3) +
+ at(3, 1) * at(0, 2) * at(1, 3) -
+ at(0, 1) * at(3, 2) * at(1, 3) -
+ at(1, 1) * at(0, 2) * at(3, 3) -
+ at(3, 1) * at(1, 2) * at(0, 3);
+ cof(2, 1) = -(at(0, 0) * at(1, 2) * at(3, 3) +
+ at(1, 0) * at(3, 2) * at(0, 3) +
+ at(3, 0) * at(0, 2) * at(1, 3) -
+ at(0, 0) * at(3, 2) * at(1, 3) -
+ at(1, 0) * at(0, 2) * at(3, 3) -
+ at(3, 0) * at(1, 2) * at(0, 3));
+ cof(2, 2) = at(0, 0) * at(1, 1) * at(3, 3) +
+ at(1, 0) * at(3, 1) * at(0, 3) +
+ at(3, 0) * at(0, 1) * at(1, 3) -
+ at(0, 0) * at(3, 1) * at(1, 3) -
+ at(1, 0) * at(0, 1) * at(3, 3) -
+ at(3, 0) * at(1, 1) * at(0, 3);
+ cof(2, 3) = -(at(0, 0) * at(1, 1) * at(3, 2) +
+ at(1, 0) * at(3, 1) * at(0, 2) +
+ at(3, 0) * at(0, 1) * at(1, 2) -
+ at(0, 0) * at(3, 1) * at(1, 2) -
+ at(1, 0) * at(0, 1) * at(3, 2) -
+ at(3, 0) * at(1, 1) * at(0, 2));
+ cof(3, 0) = -(at(0, 1) * at(1, 2) * at(2, 3) +
+ at(1, 1) * at(2, 2) * at(0, 3) +
+ at(2, 1) * at(0, 2) * at(1, 3) -
+ at(0, 1) * at(2, 2) * at(1, 3) -
+ at(1, 1) * at(0, 2) * at(2, 3) -
+ at(2, 1) * at(1, 2) * at(0, 3));
+ cof(3, 1) = at(0, 0) * at(1, 2) * at(2, 3) +
+ at(1, 0) * at(2, 2) * at(0, 3) +
+ at(2, 0) * at(0, 2) * at(1, 3) -
+ at(0, 0) * at(2, 2) * at(1, 3) -
+ at(1, 0) * at(0, 2) * at(2, 3) -
+ at(2, 0) * at(1, 2) * at(0, 3);
+ cof(3, 2) = -(at(0, 0) * at(1, 1) * at(2, 3) +
+ at(1, 0) * at(2, 1) * at(0, 3) +
+ at(2, 0) * at(0, 1) * at(1, 3) -
+ at(0, 0) * at(2, 1) * at(1, 3) -
+ at(1, 0) * at(0, 1) * at(2, 3) -
+ at(2, 0) * at(1, 1) * at(0, 3));
+ cof(3, 3) = at(0, 0) * at(1, 1) * at(2, 2) +
+ at(1, 0) * at(2, 1) * at(0, 2) +
+ at(2, 0) * at(0, 1) * at(1, 2) -
+ at(0, 0) * at(2, 1) * at(1, 2) -
+ at(1, 0) * at(0, 1) * at(2, 2) -
+ at(2, 0) * at(1, 1) * at(0, 2);
+ break;
+
+ default:
+ UNREACHABLE();
+ break;
+ }
+
+ // The inverse of A is the transpose of the cofactor matrix times the reciprocal of the determinant of A.
+ Matrix<T> adjugateMatrix(cof.transpose());
+ T det = determinant();
+ Matrix<T> result(std::vector<T>(mElements.size()), rows(), columns());
+ for (unsigned int i = 0; i < rows(); i++)
+ for (unsigned int j = 0; j < columns(); j++)
+ result(i, j) = det ? adjugateMatrix(i, j) / det : T();
+
+ return result;
+ }
+
+ private:
+ std::vector<T> mElements;
+ unsigned int mRows;
+ unsigned int mCols;
+};
+
+} // namespace angle
+
+#endif // COMMON_MATRIX_UTILS_H_
+
diff --git a/src/3rdparty/angle/src/common/platform.h b/src/3rdparty/angle/src/common/platform.h
index 3a2aa91bed..be4cb94987 100644
--- a/src/3rdparty/angle/src/common/platform.h
+++ b/src/3rdparty/angle/src/common/platform.h
@@ -53,9 +53,7 @@
# if defined(ANGLE_ENABLE_D3D9)
# include <d3d9.h>
-# if !defined(ANGLE_TRANSLATOR_IMPLEMENTATION)
# include <d3dcompiler.h>
-# endif
# endif
# if defined(ANGLE_ENABLE_D3D11)
@@ -72,9 +70,7 @@
# include <d3d11_1.h>
# include <dxgi1_2.h>
# endif
-# if !defined(ANGLE_TRANSLATOR_IMPLEMENTATION)
# include <d3dcompiler.h>
-# endif
# endif
# if defined(ANGLE_ENABLE_WINDOWS_STORE)
@@ -87,11 +83,6 @@
# endif
# endif
-# if defined(_MSC_VER) && (_MSC_VER <= 1600)
-# define final
-# define override
-# endif
-
# undef near
# undef far
#endif
diff --git a/src/3rdparty/angle/src/common/string_utils.cpp b/src/3rdparty/angle/src/common/string_utils.cpp
new file mode 100644
index 0000000000..acb0376bf9
--- /dev/null
+++ b/src/3rdparty/angle/src/common/string_utils.cpp
@@ -0,0 +1,136 @@
+//
+// Copyright 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.
+//
+// string_utils:
+// String helper functions.
+//
+
+#include "string_utils.h"
+
+#include <fstream>
+#include <sstream>
+
+namespace angle
+{
+
+const char kWhitespaceASCII[] = " \f\n\r\t\v";
+
+std::vector<std::string> SplitString(const std::string &input,
+ const std::string &delimiters,
+ WhitespaceHandling whitespace,
+ SplitResult resultType)
+{
+ std::vector<std::string> result;
+ if (input.empty())
+ {
+ return result;
+ }
+
+ std::string::size_type start = 0;
+ while (start != std::string::npos)
+ {
+ auto end = input.find_first_of(delimiters, start);
+
+ std::string piece;
+ if (end == std::string::npos)
+ {
+ piece = input.substr(start);
+ start = std::string::npos;
+ }
+ else
+ {
+ piece = input.substr(start, end - start);
+ start = end + 1;
+ }
+
+ if (whitespace == TRIM_WHITESPACE)
+ {
+ piece = TrimString(piece, kWhitespaceASCII);
+ }
+
+ if (resultType == SPLIT_WANT_ALL || !piece.empty())
+ {
+ result.push_back(piece);
+ }
+ }
+
+ return result;
+}
+
+void SplitStringAlongWhitespace(const std::string &input,
+ std::vector<std::string> *tokensOut)
+{
+
+ std::istringstream stream(input);
+ std::string line;
+
+ while (std::getline(stream, line))
+ {
+ size_t prev = 0, pos;
+ while ((pos = line.find_first_of(kWhitespaceASCII, prev)) != std::string::npos)
+ {
+ if (pos > prev)
+ tokensOut->push_back(line.substr(prev, pos - prev));
+ prev = pos + 1;
+ }
+ if (prev < line.length())
+ tokensOut->push_back(line.substr(prev, std::string::npos));
+ }
+}
+
+std::string TrimString(const std::string &input, const std::string &trimChars)
+{
+ auto begin = input.find_first_not_of(trimChars);
+ if (begin == std::string::npos)
+ {
+ return "";
+ }
+
+ std::string::size_type end = input.find_last_not_of(trimChars);
+ if (end == std::string::npos)
+ {
+ return input.substr(begin);
+ }
+
+ return input.substr(begin, end - begin + 1);
+}
+
+bool HexStringToUInt(const std::string &input, unsigned int *uintOut)
+{
+ unsigned int offset = 0;
+
+ if (input.size() >= 2 && input[0] == '0' && input[1] == 'x')
+ {
+ offset = 2u;
+ }
+
+ // Simple validity check
+ if (input.find_first_not_of("0123456789ABCDEFabcdef", offset) != std::string::npos)
+ {
+ return false;
+ }
+
+ std::stringstream inStream(input);
+ inStream >> std::hex >> *uintOut;
+ return !inStream.fail();
+}
+
+bool ReadFileToString(const std::string &path, std::string *stringOut)
+{
+ std::ifstream inFile(path.c_str());
+ if (inFile.fail())
+ {
+ return false;
+ }
+
+ inFile.seekg(0, std::ios::end);
+ stringOut->reserve(static_cast<std::string::size_type>(inFile.tellg()));
+ inFile.seekg(0, std::ios::beg);
+
+ stringOut->assign(std::istreambuf_iterator<char>(inFile), std::istreambuf_iterator<char>());
+ return !inFile.fail();
+}
+
+}
diff --git a/src/3rdparty/angle/src/common/string_utils.h b/src/3rdparty/angle/src/common/string_utils.h
new file mode 100644
index 0000000000..131b17e086
--- /dev/null
+++ b/src/3rdparty/angle/src/common/string_utils.h
@@ -0,0 +1,49 @@
+//
+// Copyright 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.
+//
+// string_utils:
+// String helper functions.
+//
+
+#ifndef LIBANGLE_STRING_UTILS_H_
+#define LIBANGLE_STRING_UTILS_H_
+
+#include <string>
+#include <vector>
+
+namespace angle
+{
+
+extern const char kWhitespaceASCII[];
+
+enum WhitespaceHandling
+{
+ KEEP_WHITESPACE,
+ TRIM_WHITESPACE,
+};
+
+enum SplitResult
+{
+ SPLIT_WANT_ALL,
+ SPLIT_WANT_NONEMPTY,
+};
+
+std::vector<std::string> SplitString(const std::string &input,
+ const std::string &delimiters,
+ WhitespaceHandling whitespace,
+ SplitResult resultType);
+
+void SplitStringAlongWhitespace(const std::string &input,
+ std::vector<std::string> *tokensOut);
+
+std::string TrimString(const std::string &input, const std::string &trimChars);
+
+bool HexStringToUInt(const std::string &input, unsigned int *uintOut);
+
+bool ReadFileToString(const std::string &path, std::string *stringOut);
+
+}
+
+#endif // LIBANGLE_STRING_UTILS_H_
diff --git a/src/3rdparty/angle/src/common/utilities.cpp b/src/3rdparty/angle/src/common/utilities.cpp
index 501e9c2564..2ab913b10f 100644
--- a/src/3rdparty/angle/src/common/utilities.cpp
+++ b/src/3rdparty/angle/src/common/utilities.cpp
@@ -19,6 +19,78 @@
# include <windows.graphics.display.h>
#endif
+namespace
+{
+
+template <class IndexType>
+gl::IndexRange ComputeTypedIndexRange(const IndexType *indices,
+ size_t count,
+ bool primitiveRestartEnabled,
+ GLuint primitiveRestartIndex)
+{
+ ASSERT(count > 0);
+
+ IndexType minIndex = 0;
+ IndexType maxIndex = 0;
+ size_t nonPrimitiveRestartIndices = 0;
+
+ if (primitiveRestartEnabled)
+ {
+ // Find the first non-primitive restart index to initialize the min and max values
+ size_t i = 0;
+ for (; i < count; i++)
+ {
+ if (indices[i] != primitiveRestartIndex)
+ {
+ minIndex = indices[i];
+ maxIndex = indices[i];
+ nonPrimitiveRestartIndices++;
+ break;
+ }
+ }
+
+ // Loop over the rest of the indices
+ for (; i < count; i++)
+ {
+ if (indices[i] != primitiveRestartIndex)
+ {
+ if (minIndex > indices[i])
+ {
+ minIndex = indices[i];
+ }
+ if (maxIndex < indices[i])
+ {
+ maxIndex = indices[i];
+ }
+ nonPrimitiveRestartIndices++;
+ }
+ }
+ }
+ else
+ {
+ minIndex = indices[0];
+ maxIndex = indices[0];
+ nonPrimitiveRestartIndices = count;
+
+ for (size_t i = 1; i < count; i++)
+ {
+ if (minIndex > indices[i])
+ {
+ minIndex = indices[i];
+ }
+ if (maxIndex < indices[i])
+ {
+ maxIndex = indices[i];
+ }
+ }
+ }
+
+ return gl::IndexRange(static_cast<size_t>(minIndex), static_cast<size_t>(maxIndex),
+ nonPrimitiveRestartIndices);
+}
+
+} // anonymous namespace
+
namespace gl
{
@@ -279,6 +351,39 @@ bool IsSamplerType(GLenum type)
return false;
}
+GLenum SamplerTypeToTextureType(GLenum samplerType)
+{
+ switch (samplerType)
+ {
+ case GL_SAMPLER_2D:
+ case GL_INT_SAMPLER_2D:
+ case GL_UNSIGNED_INT_SAMPLER_2D:
+ case GL_SAMPLER_2D_SHADOW:
+ return GL_TEXTURE_2D;
+
+ case GL_SAMPLER_CUBE:
+ case GL_INT_SAMPLER_CUBE:
+ case GL_UNSIGNED_INT_SAMPLER_CUBE:
+ case GL_SAMPLER_CUBE_SHADOW:
+ return GL_TEXTURE_CUBE_MAP;
+
+ case GL_SAMPLER_2D_ARRAY:
+ case GL_INT_SAMPLER_2D_ARRAY:
+ case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
+ case GL_SAMPLER_2D_ARRAY_SHADOW:
+ return GL_TEXTURE_2D_ARRAY;
+
+ case GL_SAMPLER_3D:
+ case GL_INT_SAMPLER_3D:
+ case GL_UNSIGNED_INT_SAMPLER_3D:
+ return GL_TEXTURE_3D;
+
+ default:
+ UNREACHABLE();
+ return 0;
+ }
+}
+
bool IsMatrixType(GLenum type)
{
return VariableRowCount(type) > 1;
@@ -366,6 +471,47 @@ GLenum LayerIndexToCubeMapTextureTarget(size_t index)
return FirstCubeMapTextureTarget + static_cast<GLenum>(index);
}
+IndexRange ComputeIndexRange(GLenum indexType,
+ const GLvoid *indices,
+ size_t count,
+ bool primitiveRestartEnabled)
+{
+ switch (indexType)
+ {
+ case GL_UNSIGNED_BYTE:
+ return ComputeTypedIndexRange(static_cast<const GLubyte *>(indices), count,
+ primitiveRestartEnabled,
+ GetPrimitiveRestartIndex(indexType));
+ case GL_UNSIGNED_SHORT:
+ return ComputeTypedIndexRange(static_cast<const GLushort *>(indices), count,
+ primitiveRestartEnabled,
+ GetPrimitiveRestartIndex(indexType));
+ case GL_UNSIGNED_INT:
+ return ComputeTypedIndexRange(static_cast<const GLuint *>(indices), count,
+ primitiveRestartEnabled,
+ GetPrimitiveRestartIndex(indexType));
+ default:
+ UNREACHABLE();
+ return IndexRange();
+ }
+}
+
+GLuint GetPrimitiveRestartIndex(GLenum indexType)
+{
+ switch (indexType)
+ {
+ case GL_UNSIGNED_BYTE:
+ return 0xFF;
+ case GL_UNSIGNED_SHORT:
+ return 0xFFFF;
+ case GL_UNSIGNED_INT:
+ return 0xFFFFFFFF;
+ default:
+ UNREACHABLE();
+ return 0;
+ }
+}
+
bool IsTriangleMode(GLenum drawMode)
{
switch (drawMode)
@@ -462,6 +608,146 @@ int VariableSortOrder(GLenum type)
}
}
+std::string ParseUniformName(const std::string &name, size_t *outSubscript)
+{
+ // Strip any trailing array operator and retrieve the subscript
+ size_t open = name.find_last_of('[');
+ size_t close = name.find_last_of(']');
+ bool hasIndex = (open != std::string::npos) && (close == name.length() - 1);
+ if (!hasIndex)
+ {
+ if (outSubscript)
+ {
+ *outSubscript = GL_INVALID_INDEX;
+ }
+ return name;
+ }
+
+ if (outSubscript)
+ {
+ int index = atoi(name.substr(open + 1).c_str());
+ if (index >= 0)
+ {
+ *outSubscript = index;
+ }
+ else
+ {
+ *outSubscript = GL_INVALID_INDEX;
+ }
+ }
+
+ return name.substr(0, open);
+}
+
+unsigned int ParseAndStripArrayIndex(std::string *name)
+{
+ unsigned int subscript = GL_INVALID_INDEX;
+
+ // Strip any trailing array operator and retrieve the subscript
+ size_t open = name->find_last_of('[');
+ size_t close = name->find_last_of(']');
+ if (open != std::string::npos && close == name->length() - 1)
+ {
+ subscript = atoi(name->c_str() + open + 1);
+ name->erase(open);
+ }
+
+ return subscript;
+}
+
+} // namespace gl
+
+namespace egl
+{
+static_assert(EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X_KHR - EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR == 1,
+ "Unexpected EGL cube map enum value.");
+static_assert(EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y_KHR - EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR == 2,
+ "Unexpected EGL cube map enum value.");
+static_assert(EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_KHR - EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR == 3,
+ "Unexpected EGL cube map enum value.");
+static_assert(EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z_KHR - EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR == 4,
+ "Unexpected EGL cube map enum value.");
+static_assert(EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_KHR - EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR == 5,
+ "Unexpected EGL cube map enum value.");
+
+bool IsCubeMapTextureTarget(EGLenum target)
+{
+ return (target >= FirstCubeMapTextureTarget && target <= LastCubeMapTextureTarget);
+}
+
+size_t CubeMapTextureTargetToLayerIndex(EGLenum target)
+{
+ ASSERT(IsCubeMapTextureTarget(target));
+ return target - static_cast<size_t>(FirstCubeMapTextureTarget);
+}
+
+EGLenum LayerIndexToCubeMapTextureTarget(size_t index)
+{
+ ASSERT(index <= (LastCubeMapTextureTarget - FirstCubeMapTextureTarget));
+ return FirstCubeMapTextureTarget + static_cast<GLenum>(index);
+}
+
+bool IsTextureTarget(EGLenum target)
+{
+ switch (target)
+ {
+ case EGL_GL_TEXTURE_2D_KHR:
+ case EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR:
+ case EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X_KHR:
+ case EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y_KHR:
+ case EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_KHR:
+ case EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z_KHR:
+ case EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_KHR:
+ case EGL_GL_TEXTURE_3D_KHR:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+bool IsRenderbufferTarget(EGLenum target)
+{
+ return target == EGL_GL_RENDERBUFFER_KHR;
+}
+}
+
+namespace egl_gl
+{
+GLenum EGLCubeMapTargetToGLCubeMapTarget(EGLenum eglTarget)
+{
+ ASSERT(egl::IsCubeMapTextureTarget(eglTarget));
+ return gl::LayerIndexToCubeMapTextureTarget(egl::CubeMapTextureTargetToLayerIndex(eglTarget));
+}
+
+GLenum EGLImageTargetToGLTextureTarget(EGLenum eglTarget)
+{
+ switch (eglTarget)
+ {
+ case EGL_GL_TEXTURE_2D_KHR:
+ return GL_TEXTURE_2D;
+
+ case EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR:
+ case EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X_KHR:
+ case EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y_KHR:
+ case EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_KHR:
+ case EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z_KHR:
+ case EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_KHR:
+ return EGLCubeMapTargetToGLCubeMapTarget(eglTarget);
+
+ case EGL_GL_TEXTURE_3D_KHR:
+ return GL_TEXTURE_3D;
+
+ default:
+ UNREACHABLE();
+ return GL_NONE;
+ }
+}
+
+GLuint EGLClientBufferToGLObjectHandle(EGLClientBuffer buffer)
+{
+ return static_cast<GLuint>(reinterpret_cast<uintptr_t>(buffer));
+}
}
#if !defined(ANGLE_ENABLE_WINDOWS_STORE)
@@ -511,32 +797,7 @@ void writeFile(const char* path, const void* content, size_t size)
// to run, the function returns immediately, and the thread continues execution.
void ScheduleYield()
{
-#if defined(ANGLE_ENABLE_WINDOWS_STORE)
- // This implementation of Sleep exists because it is not available prior to Update 4.
- static HANDLE singletonEvent = nullptr;
- HANDLE sleepEvent = singletonEvent;
- if (!sleepEvent)
- {
- sleepEvent = CreateEventEx(nullptr, nullptr, CREATE_EVENT_MANUAL_RESET, EVENT_ALL_ACCESS);
-
- if (!sleepEvent)
- return;
-
- HANDLE previousEvent = InterlockedCompareExchangePointerRelease(&singletonEvent, sleepEvent, nullptr);
-
- if (previousEvent)
- {
- // Back out if multiple threads try to demand create at the same time.
- CloseHandle(sleepEvent);
- sleepEvent = previousEvent;
- }
- }
-
- // Emulate sleep by waiting with timeout on an event that is never signalled.
- WaitForSingleObjectEx(sleepEvent, 0, false);
-#else
Sleep(0);
-#endif
}
#endif
diff --git a/src/3rdparty/angle/src/common/utilities.h b/src/3rdparty/angle/src/common/utilities.h
index 9f7f5e03c0..dc09011a26 100644
--- a/src/3rdparty/angle/src/common/utilities.h
+++ b/src/3rdparty/angle/src/common/utilities.h
@@ -9,10 +9,15 @@
#ifndef COMMON_UTILITIES_H_
#define COMMON_UTILITIES_H_
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
#include "angle_gl.h"
#include <string>
#include <math.h>
+#include "common/mathutil.h"
+
namespace gl
{
@@ -25,6 +30,7 @@ GLenum VariableBoolVectorType(GLenum type);
int VariableRowCount(GLenum type);
int VariableColumnCount(GLenum type);
bool IsSamplerType(GLenum type);
+GLenum SamplerTypeToTextureType(GLenum samplerType);
bool IsMatrixType(GLenum type);
GLenum TransposeMatrixType(GLenum type);
int VariableRegisterCount(GLenum type);
@@ -40,6 +46,20 @@ bool IsCubeMapTextureTarget(GLenum target);
size_t CubeMapTextureTargetToLayerIndex(GLenum target);
GLenum LayerIndexToCubeMapTextureTarget(size_t index);
+// Parse the base uniform name and array index. Returns the base name of the uniform. outSubscript is
+// set to GL_INVALID_INDEX if the provided name is not an array or the array index is invalid.
+std::string ParseUniformName(const std::string &name, size_t *outSubscript);
+
+// Find the range of index values in the provided indices pointer. Primitive restart indices are
+// only counted in the range if primitive restart is disabled.
+IndexRange ComputeIndexRange(GLenum indexType,
+ const GLvoid *indices,
+ size_t count,
+ bool primitiveRestartEnabled);
+
+// Get the primitive restart index value for the given index type.
+GLuint GetPrimitiveRestartIndex(GLenum indexType);
+
bool IsTriangleMode(GLenum drawMode);
// [OpenGL ES 3.0.2] Section 2.3.1 page 14
@@ -48,6 +68,26 @@ bool IsTriangleMode(GLenum drawMode);
template <typename outT> outT iround(GLfloat value) { return static_cast<outT>(value > 0.0f ? floor(value + 0.5f) : ceil(value - 0.5f)); }
template <typename outT> outT uiround(GLfloat value) { return static_cast<outT>(value + 0.5f); }
+unsigned int ParseAndStripArrayIndex(std::string *name);
+
+} // namespace gl
+
+namespace egl
+{
+static const EGLenum FirstCubeMapTextureTarget = EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR;
+static const EGLenum LastCubeMapTextureTarget = EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_KHR;
+bool IsCubeMapTextureTarget(EGLenum target);
+size_t CubeMapTextureTargetToLayerIndex(EGLenum target);
+EGLenum LayerIndexToCubeMapTextureTarget(size_t index);
+bool IsTextureTarget(EGLenum target);
+bool IsRenderbufferTarget(EGLenum target);
+}
+
+namespace egl_gl
+{
+GLenum EGLCubeMapTargetToGLCubeMapTarget(EGLenum eglTarget);
+GLenum EGLImageTargetToGLTextureTarget(EGLenum eglTarget);
+GLuint EGLClientBufferToGLObjectHandle(EGLClientBuffer buffer);
}
#if !defined(ANGLE_ENABLE_WINDOWS_STORE)
diff --git a/src/3rdparty/angle/src/common/version.h b/src/3rdparty/angle/src/common/version.h
index 758c78d44a..e7ffa7cab3 100644
--- a/src/3rdparty/angle/src/common/version.h
+++ b/src/3rdparty/angle/src/common/version.h
@@ -12,12 +12,17 @@
#define ANGLE_MAJOR_VERSION 2
#define ANGLE_MINOR_VERSION 1
+#ifndef ANGLE_REVISION
+#define ANGLE_REVISION 0
+#endif
+
#define ANGLE_STRINGIFY(x) #x
#define ANGLE_MACRO_STRINGIFY(x) ANGLE_STRINGIFY(x)
#define ANGLE_VERSION_STRING \
ANGLE_MACRO_STRINGIFY(ANGLE_MAJOR_VERSION) "." \
ANGLE_MACRO_STRINGIFY(ANGLE_MINOR_VERSION) "." \
+ ANGLE_MACRO_STRINGIFY(ANGLE_REVISION) "." \
ANGLE_COMMIT_HASH
#endif // COMMON_VERSION_H_
diff --git a/src/3rdparty/angle/src/compiler/preprocessor/DiagnosticsBase.cpp b/src/3rdparty/angle/src/compiler/preprocessor/DiagnosticsBase.cpp
index cf60bc2349..68c6e9cea4 100644
--- a/src/3rdparty/angle/src/compiler/preprocessor/DiagnosticsBase.cpp
+++ b/src/3rdparty/angle/src/compiler/preprocessor/DiagnosticsBase.cpp
@@ -78,6 +78,8 @@ std::string Diagnostics::message(ID id)
return "Not enough arguments for macro";
case PP_MACRO_TOO_MANY_ARGS:
return "Too many arguments for macro";
+ case PP_MACRO_DUPLICATE_PARAMETER_NAMES:
+ return "duplicate macro parameter name";
case PP_CONDITIONAL_ENDIF_WITHOUT_IF:
return "unexpected #endif found without a matching #if";
case PP_CONDITIONAL_ELSE_WITHOUT_IF:
@@ -103,12 +105,16 @@ std::string Diagnostics::message(ID id)
case PP_VERSION_NOT_FIRST_STATEMENT:
return "#version directive must occur before anything else, "
"except for comments and white space";
+ case PP_VERSION_NOT_FIRST_LINE_ESSL3:
+ return "#version directive must occur on the first line of the shader";
case PP_INVALID_LINE_NUMBER:
return "invalid line number";
case PP_INVALID_FILE_NUMBER:
return "invalid file number";
case PP_INVALID_LINE_DIRECTIVE:
return "invalid line directive";
+ case PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL3:
+ return "extension directive must occur before any non-preprocessor tokens in ESSL3";
// Errors end.
// Warnings begin.
case PP_EOF_IN_DIRECTIVE:
@@ -117,6 +123,10 @@ std::string Diagnostics::message(ID id)
return "unexpected token after conditional expression";
case PP_UNRECOGNIZED_PRAGMA:
return "unrecognized pragma";
+ case PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL1:
+ return "extension directive should occur before any non-preprocessor tokens";
+ case PP_WARNING_MACRO_NAME_RESERVED:
+ return "macro name with a double underscore is reserved - unintented behavior is possible";
// Warnings end.
default:
assert(false);
diff --git a/src/3rdparty/angle/src/compiler/preprocessor/DiagnosticsBase.h b/src/3rdparty/angle/src/compiler/preprocessor/DiagnosticsBase.h
index 5922d03857..d26c174f01 100644
--- a/src/3rdparty/angle/src/compiler/preprocessor/DiagnosticsBase.h
+++ b/src/3rdparty/angle/src/compiler/preprocessor/DiagnosticsBase.h
@@ -46,27 +46,32 @@ class Diagnostics
PP_MACRO_UNTERMINATED_INVOCATION,
PP_MACRO_TOO_FEW_ARGS,
PP_MACRO_TOO_MANY_ARGS,
+ PP_MACRO_DUPLICATE_PARAMETER_NAMES,
PP_CONDITIONAL_ENDIF_WITHOUT_IF,
PP_CONDITIONAL_ELSE_WITHOUT_IF,
PP_CONDITIONAL_ELSE_AFTER_ELSE,
PP_CONDITIONAL_ELIF_WITHOUT_IF,
PP_CONDITIONAL_ELIF_AFTER_ELSE,
PP_CONDITIONAL_UNTERMINATED,
+ PP_CONDITIONAL_UNEXPECTED_TOKEN,
PP_INVALID_EXTENSION_NAME,
PP_INVALID_EXTENSION_BEHAVIOR,
PP_INVALID_EXTENSION_DIRECTIVE,
PP_INVALID_VERSION_NUMBER,
PP_INVALID_VERSION_DIRECTIVE,
PP_VERSION_NOT_FIRST_STATEMENT,
+ PP_VERSION_NOT_FIRST_LINE_ESSL3,
PP_INVALID_LINE_NUMBER,
PP_INVALID_FILE_NUMBER,
PP_INVALID_LINE_DIRECTIVE,
+ PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL3,
PP_ERROR_END,
PP_WARNING_BEGIN,
PP_EOF_IN_DIRECTIVE,
- PP_CONDITIONAL_UNEXPECTED_TOKEN,
PP_UNRECOGNIZED_PRAGMA,
+ PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL1,
+ PP_WARNING_MACRO_NAME_RESERVED,
PP_WARNING_END
};
diff --git a/src/3rdparty/angle/src/compiler/preprocessor/DirectiveParser.cpp b/src/3rdparty/angle/src/compiler/preprocessor/DirectiveParser.cpp
index 7803ee845a..2faa331378 100644
--- a/src/3rdparty/angle/src/compiler/preprocessor/DirectiveParser.cpp
+++ b/src/3rdparty/angle/src/compiler/preprocessor/DirectiveParser.cpp
@@ -6,6 +6,7 @@
#include "DirectiveParser.h"
+#include <algorithm>
#include <cassert>
#include <cstdlib>
#include <sstream>
@@ -118,14 +119,12 @@ void skipUntilEOD(pp::Lexer *lexer, pp::Token *token)
bool isMacroNameReserved(const std::string &name)
{
// Names prefixed with "GL_" are reserved.
- if (name.substr(0, 3) == "GL_")
- return true;
-
- // Names containing two consecutive underscores are reserved.
- if (name.find("__") != std::string::npos)
- return true;
+ return (name.substr(0, 3) == "GL_");
+}
- return false;
+bool hasDoubleUnderscores(const std::string &name)
+{
+ return (name.find("__") != std::string::npos);
}
bool isMacroPredefined(const std::string &name,
@@ -140,80 +139,17 @@ bool isMacroPredefined(const std::string &name,
namespace pp
{
-class DefinedParser : public Lexer
-{
- public:
- DefinedParser(Lexer *lexer,
- const MacroSet *macroSet,
- Diagnostics *diagnostics)
- : mLexer(lexer),
- mMacroSet(macroSet),
- mDiagnostics(diagnostics)
- {
- }
-
- protected:
- virtual void lex(Token *token)
- {
- const char kDefined[] = "defined";
-
- mLexer->lex(token);
- if (token->type != Token::IDENTIFIER)
- return;
- if (token->text != kDefined)
- return;
-
- bool paren = false;
- mLexer->lex(token);
- if (token->type == '(')
- {
- paren = true;
- mLexer->lex(token);
- }
-
- if (token->type != Token::IDENTIFIER)
- {
- mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
- token->location, token->text);
- skipUntilEOD(mLexer, token);
- return;
- }
- MacroSet::const_iterator iter = mMacroSet->find(token->text);
- std::string expression = iter != mMacroSet->end() ? "1" : "0";
-
- if (paren)
- {
- mLexer->lex(token);
- if (token->type != ')')
- {
- mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
- token->location, token->text);
- skipUntilEOD(mLexer, token);
- return;
- }
- }
-
- // We have a valid defined operator.
- // Convert the current token into a CONST_INT token.
- token->type = Token::CONST_INT;
- token->text = expression;
- }
-
- private:
- Lexer *mLexer;
- const MacroSet *mMacroSet;
- Diagnostics *mDiagnostics;
-};
-
DirectiveParser::DirectiveParser(Tokenizer *tokenizer,
MacroSet *macroSet,
Diagnostics *diagnostics,
DirectiveHandler *directiveHandler)
: mPastFirstStatement(false),
+ mSeenNonPreprocessorToken(false),
mTokenizer(tokenizer),
mMacroSet(macroSet),
mDiagnostics(diagnostics),
- mDirectiveHandler(directiveHandler)
+ mDirectiveHandler(directiveHandler),
+ mShaderVersion(100)
{
}
@@ -228,6 +164,10 @@ void DirectiveParser::lex(Token *token)
parseDirective(token);
mPastFirstStatement = true;
}
+ else if (!isEOD(token))
+ {
+ mSeenNonPreprocessorToken = true;
+ }
if (token->type == Token::LAST)
{
@@ -349,6 +289,16 @@ void DirectiveParser::parseDefine(Token *token)
token->location, token->text);
return;
}
+ // Using double underscores is allowed, but may result in unintended
+ // behavior, so a warning is issued. At the time of writing this was
+ // specified in ESSL 3.10, but the intent judging from Khronos
+ // discussions and dEQP tests was that double underscores should be
+ // allowed in earlier ESSL versions too.
+ if (hasDoubleUnderscores(token->text))
+ {
+ mDiagnostics->report(Diagnostics::PP_WARNING_MACRO_NAME_RESERVED, token->location,
+ token->text);
+ }
Macro macro;
macro.type = Macro::kTypeObj;
@@ -364,6 +314,14 @@ void DirectiveParser::parseDefine(Token *token)
mTokenizer->lex(token);
if (token->type != Token::IDENTIFIER)
break;
+
+ if (std::find(macro.parameters.begin(), macro.parameters.end(), token->text) != macro.parameters.end())
+ {
+ mDiagnostics->report(Diagnostics::PP_MACRO_DUPLICATE_PARAMETER_NAMES,
+ token->location, token->text);
+ return;
+ }
+
macro.parameters.push_back(token->text);
mTokenizer->lex(token); // Get ','.
@@ -435,6 +393,12 @@ void DirectiveParser::parseUndef(Token *token)
}
mTokenizer->lex(token);
+ if (!isEOD(token))
+ {
+ mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
+ token->location, token->text);
+ skipUntilEOD(mTokenizer, token);
+ }
}
void DirectiveParser::parseIf(Token *token)
@@ -486,7 +450,7 @@ void DirectiveParser::parseElse(Token *token)
block.skipGroup = block.foundValidGroup;
block.foundValidGroup = true;
- // Warn if there are extra tokens after #else.
+ // Check if there are extra tokens after #else.
mTokenizer->lex(token);
if (!isEOD(token))
{
@@ -550,7 +514,7 @@ void DirectiveParser::parseEndif(Token *token)
mConditionalStack.pop_back();
- // Warn if there are tokens after #endif.
+ // Check if there are tokens after #endif.
mTokenizer->lex(token);
if (!isEOD(token))
{
@@ -699,6 +663,20 @@ void DirectiveParser::parseExtension(Token *token)
token->location, token->text);
valid = false;
}
+ if (valid && mSeenNonPreprocessorToken)
+ {
+ if (mShaderVersion >= 300)
+ {
+ mDiagnostics->report(Diagnostics::PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL3,
+ token->location, token->text);
+ valid = false;
+ }
+ else
+ {
+ mDiagnostics->report(Diagnostics::PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL1,
+ token->location, token->text);
+ }
+ }
if (valid)
mDirectiveHandler->handleExtension(token->location, name, behavior);
}
@@ -775,9 +753,18 @@ void DirectiveParser::parseVersion(Token *token)
valid = false;
}
+ if (valid && version >= 300 && token->location.line > 1)
+ {
+ mDiagnostics->report(Diagnostics::PP_VERSION_NOT_FIRST_LINE_ESSL3,
+ token->location, token->text);
+ valid = false;
+ }
+
if (valid)
{
mDirectiveHandler->handleVersion(token->location, version);
+ mShaderVersion = version;
+ PredefineMacro(mMacroSet, "__VERSION__", version);
}
}
@@ -785,72 +772,60 @@ void DirectiveParser::parseLine(Token *token)
{
assert(getDirective(token) == DIRECTIVE_LINE);
- enum State
- {
- LINE_NUMBER,
- FILE_NUMBER
- };
-
bool valid = true;
+ bool parsedFileNumber = false;
int line = 0, file = 0;
- int state = LINE_NUMBER;
- MacroExpander macroExpander(mTokenizer, mMacroSet, mDiagnostics);
+ MacroExpander macroExpander(mTokenizer, mMacroSet, mDiagnostics, false);
+
+ // Lex the first token after "#line" so we can check it for EOD.
macroExpander.lex(token);
- while ((token->type != '\n') && (token->type != Token::LAST))
+
+ if (isEOD(token))
{
- switch (state++)
+ mDiagnostics->report(Diagnostics::PP_INVALID_LINE_DIRECTIVE, token->location, token->text);
+ valid = false;
+ }
+ else
+ {
+ ExpressionParser expressionParser(&macroExpander, mDiagnostics);
+ ExpressionParser::ErrorSettings errorSettings;
+
+ // See GLES3 section 12.42
+ errorSettings.integerLiteralsMustFit32BitSignedRange = true;
+
+ errorSettings.unexpectedIdentifier = Diagnostics::PP_INVALID_LINE_NUMBER;
+ // The first token was lexed earlier to check if it was EOD. Include
+ // the token in parsing for a second time by setting the
+ // parsePresetToken flag to true.
+ expressionParser.parse(token, &line, true, errorSettings, &valid);
+ if (!isEOD(token) && valid)
+ {
+ errorSettings.unexpectedIdentifier = Diagnostics::PP_INVALID_FILE_NUMBER;
+ // After parsing the line expression expressionParser has also
+ // advanced to the first token of the file expression - this is the
+ // token that makes the parser reduce the "input" rule for the line
+ // expression and stop. So we're using parsePresetToken = true here
+ // as well.
+ expressionParser.parse(token, &file, true, errorSettings, &valid);
+ parsedFileNumber = true;
+ }
+ if (!isEOD(token))
{
- case LINE_NUMBER:
- if (valid && (token->type != Token::CONST_INT))
- {
- mDiagnostics->report(Diagnostics::PP_INVALID_LINE_NUMBER,
- token->location, token->text);
- valid = false;
- }
- if (valid && !token->iValue(&line))
- {
- mDiagnostics->report(Diagnostics::PP_INTEGER_OVERFLOW,
- token->location, token->text);
- valid = false;
- }
- break;
- case FILE_NUMBER:
- if (valid && (token->type != Token::CONST_INT))
- {
- mDiagnostics->report(Diagnostics::PP_INVALID_FILE_NUMBER,
- token->location, token->text);
- valid = false;
- }
- if (valid && !token->iValue(&file))
- {
- mDiagnostics->report(Diagnostics::PP_INTEGER_OVERFLOW,
- token->location, token->text);
- valid = false;
- }
- break;
- default:
if (valid)
{
mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
token->location, token->text);
valid = false;
}
- break;
+ skipUntilEOD(mTokenizer, token);
}
- macroExpander.lex(token);
}
- if (valid && (state != FILE_NUMBER) && (state != FILE_NUMBER + 1))
- {
- mDiagnostics->report(Diagnostics::PP_INVALID_LINE_DIRECTIVE,
- token->location, token->text);
- valid = false;
- }
if (valid)
{
mTokenizer->setLineNumber(line);
- if (state == FILE_NUMBER + 1)
+ if (parsedFileNumber)
mTokenizer->setFileNumber(file);
}
}
@@ -910,15 +885,18 @@ int DirectiveParser::parseExpressionIf(Token *token)
assert((getDirective(token) == DIRECTIVE_IF) ||
(getDirective(token) == DIRECTIVE_ELIF));
- DefinedParser definedParser(mTokenizer, mMacroSet, mDiagnostics);
- MacroExpander macroExpander(&definedParser, mMacroSet, mDiagnostics);
+ MacroExpander macroExpander(mTokenizer, mMacroSet, mDiagnostics, true);
ExpressionParser expressionParser(&macroExpander, mDiagnostics);
int expression = 0;
- macroExpander.lex(token);
- expressionParser.parse(token, &expression);
+ ExpressionParser::ErrorSettings errorSettings;
+ errorSettings.integerLiteralsMustFit32BitSignedRange = false;
+ errorSettings.unexpectedIdentifier = Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN;
+
+ bool valid = true;
+ expressionParser.parse(token, &expression, false, errorSettings, &valid);
- // Warn if there are tokens after #if expression.
+ // Check if there are tokens after #if expression.
if (!isEOD(token))
{
mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
@@ -946,7 +924,7 @@ int DirectiveParser::parseExpressionIfdef(Token *token)
MacroSet::const_iterator iter = mMacroSet->find(token->text);
int expression = iter != mMacroSet->end() ? 1 : 0;
- // Warn if there are tokens after #ifdef expression.
+ // Check if there are tokens after #ifdef expression.
mTokenizer->lex(token);
if (!isEOD(token))
{
diff --git a/src/3rdparty/angle/src/compiler/preprocessor/DirectiveParser.h b/src/3rdparty/angle/src/compiler/preprocessor/DirectiveParser.h
index e1acdbb8d0..2888e289ce 100644
--- a/src/3rdparty/angle/src/compiler/preprocessor/DirectiveParser.h
+++ b/src/3rdparty/angle/src/compiler/preprocessor/DirectiveParser.h
@@ -27,7 +27,7 @@ class DirectiveParser : public Lexer
Diagnostics *diagnostics,
DirectiveHandler *directiveHandler);
- virtual void lex(Token *token);
+ void lex(Token *token) override;
private:
PP_DISALLOW_COPY_AND_ASSIGN(DirectiveParser);
@@ -70,11 +70,14 @@ class DirectiveParser : public Lexer
}
};
bool mPastFirstStatement;
+ bool mSeenNonPreprocessorToken; // Tracks if a non-preprocessor token has been seen yet. Some macros, such as
+ // #extension must be declared before all shader code.
std::vector<ConditionalBlock> mConditionalStack;
Tokenizer *mTokenizer;
MacroSet *mMacroSet;
Diagnostics *mDiagnostics;
DirectiveHandler *mDirectiveHandler;
+ int mShaderVersion;
};
} // namespace pp
diff --git a/src/3rdparty/angle/src/compiler/preprocessor/ExpressionParser.h b/src/3rdparty/angle/src/compiler/preprocessor/ExpressionParser.h
index 4b80ba7261..841c67b61c 100644
--- a/src/3rdparty/angle/src/compiler/preprocessor/ExpressionParser.h
+++ b/src/3rdparty/angle/src/compiler/preprocessor/ExpressionParser.h
@@ -7,21 +7,31 @@
#ifndef COMPILER_PREPROCESSOR_EXPRESSIONPARSER_H_
#define COMPILER_PREPROCESSOR_EXPRESSIONPARSER_H_
+#include "DiagnosticsBase.h"
#include "pp_utils.h"
namespace pp
{
-class Diagnostics;
class Lexer;
struct Token;
class ExpressionParser
{
public:
+ struct ErrorSettings
+ {
+ Diagnostics::ID unexpectedIdentifier;
+ bool integerLiteralsMustFit32BitSignedRange;
+ };
+
ExpressionParser(Lexer *lexer, Diagnostics *diagnostics);
- bool parse(Token *token, int *result);
+ bool parse(Token *token,
+ int *result,
+ bool parsePresetToken,
+ const ErrorSettings &errorSettings,
+ bool *valid);
private:
PP_DISALLOW_COPY_AND_ASSIGN(ExpressionParser);
diff --git a/src/3rdparty/angle/src/compiler/preprocessor/ExpressionParser.y b/src/3rdparty/angle/src/compiler/preprocessor/ExpressionParser.y
index 8caf36bfc8..7b5d9e9cee 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 4702)
+#pragma warning(disable: 4065 4244 4701 4702)
#endif
#include "ExpressionParser.h"
@@ -52,6 +52,7 @@ typedef __int64 YYSTYPE;
#include <stdint.h>
typedef intmax_t YYSTYPE;
#endif // _MSC_VER
+
#define YYENABLE_NLS 0
#define YYLTYPE_IS_TRIVIAL 1
#define YYSTYPE_IS_TRIVIAL 1
@@ -64,6 +65,17 @@ struct Context
pp::Lexer* lexer;
pp::Token* token;
int* result;
+ bool parsePresetToken;
+
+ pp::ExpressionParser::ErrorSettings errorSettings;
+ bool *valid;
+
+ void startIgnoreErrors() { ++ignoreErrors; }
+ void endIgnoreErrors() { --ignoreErrors; }
+
+ bool isIgnoringErrors() { return ignoreErrors > 0; }
+
+ int ignoreErrors;
};
} // namespace
%}
@@ -79,6 +91,7 @@ static void yyerror(Context* context, const char* reason);
%}
%token TOK_CONST_INT
+%token TOK_IDENTIFIER
%left TOK_OP_OR
%left TOK_OP_AND
%left '|'
@@ -102,11 +115,58 @@ input
expression
: TOK_CONST_INT
- | expression TOK_OP_OR expression {
- $$ = $1 || $3;
+ | TOK_IDENTIFIER {
+ if (!context->isIgnoringErrors())
+ {
+ // This rule should be applied right after the token is lexed, so we can
+ // refer to context->token in the error message.
+ context->diagnostics->report(context->errorSettings.unexpectedIdentifier,
+ context->token->location, context->token->text);
+ *(context->valid) = false;
+ }
+ $$ = $1;
}
- | expression TOK_OP_AND expression {
- $$ = $1 && $3;
+ | expression TOK_OP_OR {
+ if ($1 != 0)
+ {
+ // Ignore errors in the short-circuited part of the expression.
+ // ESSL3.00 section 3.4:
+ // If an operand is not evaluated, the presence of undefined identifiers
+ // in the operand will not cause an error.
+ // Unevaluated division by zero should not cause an error either.
+ context->startIgnoreErrors();
+ }
+ } expression {
+ if ($1 != 0)
+ {
+ context->endIgnoreErrors();
+ $$ = static_cast<YYSTYPE>(1);
+ }
+ else
+ {
+ $$ = $1 || $4;
+ }
+ }
+ | expression TOK_OP_AND {
+ if ($1 == 0)
+ {
+ // Ignore errors in the short-circuited part of the expression.
+ // ESSL3.00 section 3.4:
+ // If an operand is not evaluated, the presence of undefined identifiers
+ // in the operand will not cause an error.
+ // Unevaluated division by zero should not cause an error either.
+ context->startIgnoreErrors();
+ }
+ } expression {
+ if ($1 == 0)
+ {
+ context->endIgnoreErrors();
+ $$ = static_cast<YYSTYPE>(0);
+ }
+ else
+ {
+ $$ = $1 && $4;
+ }
}
| expression '|' expression {
$$ = $1 | $3;
@@ -148,28 +208,42 @@ expression
$$ = $1 + $3;
}
| expression '%' expression {
- if ($3 == 0) {
- std::ostringstream stream;
- stream << $1 << " % " << $3;
- std::string text = stream.str();
- context->diagnostics->report(pp::Diagnostics::PP_DIVISION_BY_ZERO,
- context->token->location,
- text.c_str());
- YYABORT;
- } else {
+ if ($3 == 0)
+ {
+ if (!context->isIgnoringErrors())
+ {
+ std::ostringstream stream;
+ stream << $1 << " % " << $3;
+ std::string text = stream.str();
+ context->diagnostics->report(pp::Diagnostics::PP_DIVISION_BY_ZERO,
+ context->token->location,
+ text.c_str());
+ *(context->valid) = false;
+ }
+ $$ = static_cast<YYSTYPE>(0);
+ }
+ else
+ {
$$ = $1 % $3;
}
}
| expression '/' expression {
- if ($3 == 0) {
- std::ostringstream stream;
- stream << $1 << " / " << $3;
- std::string text = stream.str();
- context->diagnostics->report(pp::Diagnostics::PP_DIVISION_BY_ZERO,
- context->token->location,
- text.c_str());
- YYABORT;
- } else {
+ if ($3 == 0)
+ {
+ if (!context->isIgnoringErrors())
+ {
+ std::ostringstream stream;
+ stream << $1 << " / " << $3;
+ std::string text = stream.str();
+ context->diagnostics->report(pp::Diagnostics::PP_DIVISION_BY_ZERO,
+ context->token->location,
+ text.c_str());
+ *(context->valid) = false;
+ }
+ $$ = static_cast<YYSTYPE>(0);
+ }
+ else
+ {
$$ = $1 / $3;
}
}
@@ -197,22 +271,35 @@ expression
int yylex(YYSTYPE *lvalp, Context *context)
{
+ pp::Token *token = context->token;
+ if (!context->parsePresetToken)
+ {
+ context->lexer->lex(token);
+ }
+ context->parsePresetToken = false;
+
int type = 0;
- pp::Token *token = context->token;
switch (token->type)
{
case pp::Token::CONST_INT: {
unsigned int val = 0;
- if (!token->uValue(&val))
+ int testVal = 0;
+ if (!token->uValue(&val) || (!token->iValue(&testVal) &&
+ context->errorSettings.integerLiteralsMustFit32BitSignedRange))
{
context->diagnostics->report(pp::Diagnostics::PP_INTEGER_OVERFLOW,
token->location, token->text);
+ *(context->valid) = false;
}
*lvalp = static_cast<YYSTYPE>(val);
type = TOK_CONST_INT;
break;
}
+ case pp::Token::IDENTIFIER:
+ *lvalp = static_cast<YYSTYPE>(-1);
+ type = TOK_IDENTIFIER;
+ break;
case pp::Token::OP_OR:
type = TOK_OP_OR;
break;
@@ -258,10 +345,6 @@ int yylex(YYSTYPE *lvalp, Context *context)
break;
}
- // Advance to the next token if the current one is valid.
- if (type != 0)
- context->lexer->lex(token);
-
return type;
}
@@ -280,13 +363,21 @@ ExpressionParser::ExpressionParser(Lexer *lexer, Diagnostics *diagnostics)
{
}
-bool ExpressionParser::parse(Token *token, int *result)
+bool ExpressionParser::parse(Token *token,
+ int *result,
+ bool parsePresetToken,
+ const ErrorSettings &errorSettings,
+ bool *valid)
{
Context context;
context.diagnostics = mDiagnostics;
context.lexer = mLexer;
context.token = token;
context.result = result;
+ context.ignoreErrors = 0;
+ context.parsePresetToken = parsePresetToken;
+ context.errorSettings = errorSettings;
+ context.valid = valid;
int ret = yyparse(&context);
switch (ret)
{
diff --git a/src/3rdparty/angle/src/compiler/preprocessor/Input.cpp b/src/3rdparty/angle/src/compiler/preprocessor/Input.cpp
index f9910a6cc3..5541d46f72 100644
--- a/src/3rdparty/angle/src/compiler/preprocessor/Input.cpp
+++ b/src/3rdparty/angle/src/compiler/preprocessor/Input.cpp
@@ -29,13 +29,75 @@ Input::Input(size_t count, const char *const string[], const int length[]) :
}
}
-size_t Input::read(char *buf, size_t maxSize)
+const char *Input::skipChar()
+{
+ // This function should only be called when there is a character to skip.
+ assert(mReadLoc.cIndex < mLength[mReadLoc.sIndex]);
+ ++mReadLoc.cIndex;
+ if (mReadLoc.cIndex == mLength[mReadLoc.sIndex])
+ {
+ ++mReadLoc.sIndex;
+ mReadLoc.cIndex = 0;
+ }
+ if (mReadLoc.sIndex >= mCount)
+ {
+ return nullptr;
+ }
+ return mString[mReadLoc.sIndex] + mReadLoc.cIndex;
+}
+
+size_t Input::read(char *buf, size_t maxSize, int *lineNo)
{
size_t nRead = 0;
- while ((nRead < maxSize) && (mReadLoc.sIndex < mCount))
+ // The previous call to read might have stopped copying the string when encountering a line
+ // continuation. Check for this possibility first.
+ if (mReadLoc.sIndex < mCount && maxSize > 0)
+ {
+ const char *c = mString[mReadLoc.sIndex] + mReadLoc.cIndex;
+ if ((*c) == '\\')
+ {
+ c = skipChar();
+ if (c != nullptr && (*c) == '\n')
+ {
+ // Line continuation of backslash + newline.
+ skipChar();
+ ++(*lineNo);
+ }
+ else if (c != nullptr && (*c) == '\r')
+ {
+ // Line continuation. Could be backslash + '\r\n' or just backslash + '\r'.
+ c = skipChar();
+ if (c != nullptr && (*c) == '\n')
+ {
+ skipChar();
+ }
+ ++(*lineNo);
+ }
+ else
+ {
+ // Not line continuation, so write the skipped backslash to buf.
+ *buf = '\\';
+ ++nRead;
+ }
+ }
+ }
+
+ size_t maxRead = maxSize;
+ while ((nRead < maxRead) && (mReadLoc.sIndex < mCount))
{
size_t size = mLength[mReadLoc.sIndex] - mReadLoc.cIndex;
size = std::min(size, maxSize);
+ for (size_t i = 0; i < size; ++i)
+ {
+ // Stop if a possible line continuation is encountered.
+ // It will be processed on the next call on input, which skips it
+ // and increments line number if necessary.
+ if (*(mString[mReadLoc.sIndex] + mReadLoc.cIndex + i) == '\\')
+ {
+ size = i;
+ maxRead = nRead + size; // Stop reading right before the backslash.
+ }
+ }
std::memcpy(buf + nRead, mString[mReadLoc.sIndex] + mReadLoc.cIndex, size);
nRead += size;
mReadLoc.cIndex += size;
diff --git a/src/3rdparty/angle/src/compiler/preprocessor/Input.h b/src/3rdparty/angle/src/compiler/preprocessor/Input.h
index e951cb4d5f..a1de7ddd86 100644
--- a/src/3rdparty/angle/src/compiler/preprocessor/Input.h
+++ b/src/3rdparty/angle/src/compiler/preprocessor/Input.h
@@ -33,7 +33,7 @@ class Input
return mLength[index];
}
- size_t read(char *buf, size_t maxSize);
+ size_t read(char *buf, size_t maxSize, int *lineNo);
struct Location
{
@@ -49,6 +49,10 @@ class Input
const Location &readLoc() const { return mReadLoc; }
private:
+ // Skip a character and return the next character after the one that was skipped.
+ // Return nullptr if data runs out.
+ const char *skipChar();
+
// Input.
size_t mCount;
const char * const *mString;
diff --git a/src/3rdparty/angle/src/compiler/preprocessor/Macro.cpp b/src/3rdparty/angle/src/compiler/preprocessor/Macro.cpp
index 13cb14e3dc..4c4d5fd2e2 100644
--- a/src/3rdparty/angle/src/compiler/preprocessor/Macro.cpp
+++ b/src/3rdparty/angle/src/compiler/preprocessor/Macro.cpp
@@ -6,6 +6,8 @@
#include "Macro.h"
+#include <sstream>
+
#include "Token.h"
namespace pp
@@ -19,5 +21,23 @@ bool Macro::equals(const Macro &other) const
(replacements == other.replacements);
}
+void PredefineMacro(MacroSet *macroSet, const char *name, int value)
+{
+ std::ostringstream stream;
+ stream << value;
+
+ Token token;
+ token.type = Token::CONST_INT;
+ token.text = stream.str();
+
+ Macro macro;
+ macro.predefined = true;
+ macro.type = Macro::kTypeObj;
+ macro.name = name;
+ macro.replacements.push_back(token);
+
+ (*macroSet)[name] = macro;
+}
+
} // namespace pp
diff --git a/src/3rdparty/angle/src/compiler/preprocessor/Macro.h b/src/3rdparty/angle/src/compiler/preprocessor/Macro.h
index 7662a9c5a2..31ee22c26a 100644
--- a/src/3rdparty/angle/src/compiler/preprocessor/Macro.h
+++ b/src/3rdparty/angle/src/compiler/preprocessor/Macro.h
@@ -45,6 +45,8 @@ struct Macro
typedef std::map<std::string, Macro> MacroSet;
+void PredefineMacro(MacroSet *macroSet, const char *name, int value);
+
} // namespace pp
#endif // COMPILER_PREPROCESSOR_MACRO_H_
diff --git a/src/3rdparty/angle/src/compiler/preprocessor/MacroExpander.cpp b/src/3rdparty/angle/src/compiler/preprocessor/MacroExpander.cpp
index 69e2f39069..e878ee345a 100644
--- a/src/3rdparty/angle/src/compiler/preprocessor/MacroExpander.cpp
+++ b/src/3rdparty/angle/src/compiler/preprocessor/MacroExpander.cpp
@@ -26,7 +26,7 @@ class TokenLexer : public Lexer
mIter = mTokens.begin();
}
- virtual void lex(Token *token)
+ void lex(Token *token) override
{
if (mIter == mTokens.end())
{
@@ -48,10 +48,9 @@ class TokenLexer : public Lexer
MacroExpander::MacroExpander(Lexer *lexer,
MacroSet *macroSet,
- Diagnostics *diagnostics)
- : mLexer(lexer),
- mMacroSet(macroSet),
- mDiagnostics(diagnostics)
+ Diagnostics *diagnostics,
+ bool parseDefined)
+ : mLexer(lexer), mMacroSet(macroSet), mDiagnostics(diagnostics), mParseDefined(parseDefined)
{
}
@@ -67,11 +66,54 @@ void MacroExpander::lex(Token *token)
{
while (true)
{
+ const char kDefined[] = "defined";
+
getToken(token);
if (token->type != Token::IDENTIFIER)
break;
+ // Defined operator is parsed here since it may be generated by macro expansion.
+ // Defined operator produced by macro expansion has undefined behavior according to C++
+ // spec, which the GLSL spec references (see C++14 draft spec section 16.1.4), but this
+ // behavior is needed for passing dEQP tests, which enforce stricter compatibility between
+ // implementations.
+ if (mParseDefined && token->text == kDefined)
+ {
+ bool paren = false;
+ getToken(token);
+ if (token->type == '(')
+ {
+ paren = true;
+ getToken(token);
+ }
+ if (token->type != Token::IDENTIFIER)
+ {
+ mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location,
+ token->text);
+ break;
+ }
+ auto iter = mMacroSet->find(token->text);
+ std::string expression = iter != mMacroSet->end() ? "1" : "0";
+
+ if (paren)
+ {
+ getToken(token);
+ if (token->type != ')')
+ {
+ mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location,
+ token->text);
+ break;
+ }
+ }
+
+ // We have a valid defined operator.
+ // Convert the current token into a CONST_INT token.
+ token->type = Token::CONST_INT;
+ token->text = expression;
+ break;
+ }
+
if (token->expansionDisabled())
break;
@@ -187,6 +229,12 @@ bool MacroExpander::expandMacro(const Macro &macro,
std::vector<Token> *replacements)
{
replacements->clear();
+
+ // In the case of an object-like macro, the replacement list gets its location
+ // from the identifier, but in the case of a function-like macro, the replacement
+ // list gets its location from the closing parenthesis of the macro invocation.
+ // This is tested by dEQP-GLES3.functional.shaders.preprocessor.predefined_macros.*
+ SourceLocation replacementLocation = identifier.location;
if (macro.type == Macro::kTypeObj)
{
replacements->assign(macro.replacements.begin(),
@@ -218,7 +266,7 @@ bool MacroExpander::expandMacro(const Macro &macro,
assert(macro.type == Macro::kTypeFunc);
std::vector<MacroArg> args;
args.reserve(macro.parameters.size());
- if (!collectMacroArgs(macro, identifier, &args))
+ if (!collectMacroArgs(macro, identifier, &args, &replacementLocation))
return false;
replaceMacroParams(macro, args, replacements);
@@ -234,14 +282,15 @@ bool MacroExpander::expandMacro(const Macro &macro,
repl.setAtStartOfLine(identifier.atStartOfLine());
repl.setHasLeadingSpace(identifier.hasLeadingSpace());
}
- repl.location = identifier.location;
+ repl.location = replacementLocation;
}
return true;
}
bool MacroExpander::collectMacroArgs(const Macro &macro,
const Token &identifier,
- std::vector<MacroArg> *args)
+ std::vector<MacroArg> *args,
+ SourceLocation *closingParenthesisLocation)
{
Token token;
getToken(&token);
@@ -271,6 +320,7 @@ bool MacroExpander::collectMacroArgs(const Macro &macro,
case ')':
--openParens;
isArg = openParens != 0;
+ *closingParenthesisLocation = token.location;
break;
case ',':
// The individual arguments are separated by comma tokens, but
@@ -317,7 +367,7 @@ bool MacroExpander::collectMacroArgs(const Macro &macro,
{
MacroArg &arg = args->at(i);
TokenLexer lexer(&arg);
- MacroExpander expander(&lexer, mMacroSet, mDiagnostics);
+ MacroExpander expander(&lexer, mMacroSet, mDiagnostics, mParseDefined);
arg.clear();
expander.lex(&token);
diff --git a/src/3rdparty/angle/src/compiler/preprocessor/MacroExpander.h b/src/3rdparty/angle/src/compiler/preprocessor/MacroExpander.h
index 5a0c7751a8..3cc860d753 100644
--- a/src/3rdparty/angle/src/compiler/preprocessor/MacroExpander.h
+++ b/src/3rdparty/angle/src/compiler/preprocessor/MacroExpander.h
@@ -19,14 +19,15 @@ namespace pp
{
class Diagnostics;
+struct SourceLocation;
class MacroExpander : public Lexer
{
public:
- MacroExpander(Lexer *lexer, MacroSet *macroSet, Diagnostics *diagnostics);
- virtual ~MacroExpander();
+ MacroExpander(Lexer *lexer, MacroSet *macroSet, Diagnostics *diagnostics, bool parseDefined);
+ ~MacroExpander() override;
- virtual void lex(Token *token);
+ void lex(Token *token) override;
private:
PP_DISALLOW_COPY_AND_ASSIGN(MacroExpander);
@@ -45,7 +46,8 @@ class MacroExpander : public Lexer
typedef std::vector<Token> MacroArg;
bool collectMacroArgs(const Macro &macro,
const Token &identifier,
- std::vector<MacroArg> *args);
+ std::vector<MacroArg> *args,
+ SourceLocation *closingParenthesisLocation);
void replaceMacroParams(const Macro &macro,
const std::vector<MacroArg> &args,
std::vector<Token> *replacements);
@@ -79,6 +81,7 @@ class MacroExpander : public Lexer
Lexer *mLexer;
MacroSet *mMacroSet;
Diagnostics *mDiagnostics;
+ bool mParseDefined;
std::auto_ptr<Token> mReserveToken;
std::vector<MacroContext *> mContextStack;
diff --git a/src/3rdparty/angle/src/compiler/preprocessor/Preprocessor.cpp b/src/3rdparty/angle/src/compiler/preprocessor/Preprocessor.cpp
index 3522fa1abb..aeb9c46f9d 100644
--- a/src/3rdparty/angle/src/compiler/preprocessor/Preprocessor.cpp
+++ b/src/3rdparty/angle/src/compiler/preprocessor/Preprocessor.cpp
@@ -7,7 +7,6 @@
#include "Preprocessor.h"
#include <cassert>
-#include <sstream>
#include "DiagnosticsBase.h"
#include "DirectiveParser.h"
@@ -27,12 +26,11 @@ struct PreprocessorImpl
DirectiveParser directiveParser;
MacroExpander macroExpander;
- PreprocessorImpl(Diagnostics *diag,
- DirectiveHandler *directiveHandler)
+ PreprocessorImpl(Diagnostics *diag, DirectiveHandler *directiveHandler)
: diagnostics(diag),
tokenizer(diag),
directiveParser(&tokenizer, &macroSet, diag, directiveHandler),
- macroExpander(&directiveParser, &macroSet, diag)
+ macroExpander(&directiveParser, &macroSet, diag, false)
{
}
};
@@ -52,12 +50,12 @@ bool Preprocessor::init(size_t count,
const char * const string[],
const int length[])
{
- static const int kGLSLVersion = 100;
+ static const int kDefaultGLSLVersion = 100;
// Add standard pre-defined macros.
predefineMacro("__LINE__", 0);
predefineMacro("__FILE__", 0);
- predefineMacro("__VERSION__", kGLSLVersion);
+ predefineMacro("__VERSION__", kDefaultGLSLVersion);
predefineMacro("GL_ES", 1);
return mImpl->tokenizer.init(count, string, length);
@@ -65,20 +63,7 @@ bool Preprocessor::init(size_t count,
void Preprocessor::predefineMacro(const char *name, int value)
{
- std::ostringstream stream;
- stream << value;
-
- Token token;
- token.type = Token::CONST_INT;
- token.text = stream.str();
-
- Macro macro;
- macro.predefined = true;
- macro.type = Macro::kTypeObj;
- macro.name = name;
- macro.replacements.push_back(token);
-
- mImpl->macroSet[name] = macro;
+ PredefineMacro(&mImpl->macroSet, name, value);
}
void Preprocessor::lex(Token *token)
diff --git a/src/3rdparty/angle/src/compiler/preprocessor/Tokenizer.h b/src/3rdparty/angle/src/compiler/preprocessor/Tokenizer.h
index 78eb86dd3b..49e64fa209 100644
--- a/src/3rdparty/angle/src/compiler/preprocessor/Tokenizer.h
+++ b/src/3rdparty/angle/src/compiler/preprocessor/Tokenizer.h
@@ -42,7 +42,7 @@ class Tokenizer : public Lexer
void setLineNumber(int line);
void setMaxTokenSize(size_t maxTokenSize);
- virtual void lex(Token *token);
+ void lex(Token *token) override;
private:
PP_DISALLOW_COPY_AND_ASSIGN(Tokenizer);
diff --git a/src/3rdparty/angle/src/compiler/preprocessor/Tokenizer.l b/src/3rdparty/angle/src/compiler/preprocessor/Tokenizer.l
index 89cb5c8596..d316da88b1 100644
--- a/src/3rdparty/angle/src/compiler/preprocessor/Tokenizer.l
+++ b/src/3rdparty/angle/src/compiler/preprocessor/Tokenizer.l
@@ -23,6 +23,10 @@ IF YOU MODIFY THIS FILE YOU ALSO NEED TO RUN generate_parser.sh.
}
%{
+#if defined(_MSC_VER)
+#pragma warning(disable: 4005)
+#endif
+
#include "Tokenizer.h"
#include "DiagnosticsBase.h"
@@ -31,6 +35,15 @@ IF YOU MODIFY THIS FILE YOU ALSO NEED TO RUN generate_parser.sh.
#if defined(__GNUC__)
// Triggered by the auto-generated yy_fatal_error function.
#pragma GCC diagnostic ignored "-Wmissing-noreturn"
+#elif defined(_MSC_VER)
+#pragma warning(disable: 4244)
+#endif
+
+// Workaround for flex using the register keyword, deprecated in C++11.
+#ifdef __cplusplus
+#if __cplusplus > 199711L
+#define register
+#endif
#endif
typedef std::string YYSTYPE;
@@ -64,7 +77,7 @@ typedef pp::SourceLocation YYLTYPE;
} while(0);
#define YY_INPUT(buf, result, maxSize) \
- result = yyextra->input.read(buf, maxSize);
+ result = yyextra->input.read(buf, maxSize, &yylineno);
%}
@@ -93,7 +106,7 @@ FRACTIONAL_CONSTANT ({DIGIT}*"."{DIGIT}+)|({DIGIT}+".")
/* Block comment */
/* Line breaks are just counted - not returned. */
- /* The comment is replaced by a single space. */
+ /* The comment is replaced by a single space. */
"/*" { BEGIN(COMMENT); }
<COMMENT>[^*\r\n]+
<COMMENT>"*"
diff --git a/src/3rdparty/angle/src/compiler/preprocessor/numeric_lex.h b/src/3rdparty/angle/src/compiler/preprocessor/numeric_lex.h
index 58c51b0961..b32e42253f 100644
--- a/src/3rdparty/angle/src/compiler/preprocessor/numeric_lex.h
+++ b/src/3rdparty/angle/src/compiler/preprocessor/numeric_lex.h
@@ -48,6 +48,15 @@ bool numeric_lex_int(const std::string &str, IntType *value)
template<typename FloatType>
bool numeric_lex_float(const std::string &str, FloatType *value)
{
+// On 64-bit Intel Android, istringstream is broken. Until this is fixed in
+// a newer NDK, don't use it. Android doesn't have locale support, so this
+// doesn't have to force the C locale.
+// TODO(thakis): Remove this once this bug has been fixed in the NDK and
+// that NDK has been rolled into chromium.
+#if defined(ANGLE_PLATFORM_ANDROID) && __x86_64__
+ *value = strtod(str.c_str(), nullptr);
+ return errno != ERANGE;
+#else
std::istringstream stream(str);
// Force "C" locale so that decimal character is always '.', and
// not dependent on the current locale.
@@ -55,6 +64,7 @@ bool numeric_lex_float(const std::string &str, FloatType *value)
stream >> (*value);
return !stream.fail();
+#endif
}
} // namespace pp.
diff --git a/src/3rdparty/angle/src/compiler/translator/ASTMetadataHLSL.cpp b/src/3rdparty/angle/src/compiler/translator/ASTMetadataHLSL.cpp
new file mode 100644
index 0000000000..31bfae9966
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/translator/ASTMetadataHLSL.cpp
@@ -0,0 +1,451 @@
+//
+// 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.
+//
+
+// Analysis of the AST needed for HLSL generation
+
+#include "compiler/translator/ASTMetadataHLSL.h"
+
+#include "compiler/translator/CallDAG.h"
+#include "compiler/translator/SymbolTable.h"
+
+namespace
+{
+
+// Class used to traverse the AST of a function definition, checking if the
+// function uses a gradient, and writing the set of control flow using gradients.
+// It assumes that the analysis has already been made for the function's
+// callees.
+class PullGradient : public TIntermTraverser
+{
+ public:
+ PullGradient(MetadataList *metadataList, size_t index, const CallDAG &dag)
+ : TIntermTraverser(true, false, true),
+ mMetadataList(metadataList),
+ mMetadata(&(*metadataList)[index]),
+ mIndex(index),
+ mDag(dag)
+ {
+ ASSERT(index < metadataList->size());
+ }
+
+ void traverse(TIntermAggregate *node)
+ {
+ node->traverse(this);
+ ASSERT(mParents.empty());
+ }
+
+ // Called when a gradient operation or a call to a function using a gradient is found.
+ void onGradient()
+ {
+ mMetadata->mUsesGradient = true;
+ // Mark the latest control flow as using a gradient.
+ if (!mParents.empty())
+ {
+ mMetadata->mControlFlowsContainingGradient.insert(mParents.back());
+ }
+ }
+
+ void visitControlFlow(Visit visit, TIntermNode *node)
+ {
+ if (visit == PreVisit)
+ {
+ mParents.push_back(node);
+ }
+ else if (visit == PostVisit)
+ {
+ ASSERT(mParents.back() == node);
+ mParents.pop_back();
+ // A control flow's using a gradient means its parents are too.
+ if (mMetadata->mControlFlowsContainingGradient.count(node)> 0 && !mParents.empty())
+ {
+ mMetadata->mControlFlowsContainingGradient.insert(mParents.back());
+ }
+ }
+ }
+
+ bool visitLoop(Visit visit, TIntermLoop *loop) override
+ {
+ visitControlFlow(visit, loop);
+ return true;
+ }
+
+ bool visitSelection(Visit visit, TIntermSelection *selection) override
+ {
+ visitControlFlow(visit, selection);
+ return true;
+ }
+
+ bool visitUnary(Visit visit, TIntermUnary *node) override
+ {
+ if (visit == PreVisit)
+ {
+ switch (node->getOp())
+ {
+ case EOpDFdx:
+ case EOpDFdy:
+ onGradient();
+ default:
+ break;
+ }
+ }
+
+ return true;
+ }
+
+ bool visitAggregate(Visit visit, TIntermAggregate *node) override
+ {
+ if (visit == PreVisit)
+ {
+ if (node->getOp() == EOpFunctionCall)
+ {
+ if (node->isUserDefined())
+ {
+ size_t calleeIndex = mDag.findIndex(node);
+ ASSERT(calleeIndex != CallDAG::InvalidIndex && calleeIndex < mIndex);
+ UNUSED_ASSERTION_VARIABLE(mIndex);
+
+ if ((*mMetadataList)[calleeIndex].mUsesGradient) {
+ onGradient();
+ }
+ }
+ else
+ {
+ TString name = TFunction::unmangleName(node->getName());
+
+ if (name == "texture2D" ||
+ name == "texture2DProj" ||
+ name == "textureCube")
+ {
+ onGradient();
+ }
+ }
+ }
+ }
+
+ return true;
+ }
+
+ private:
+ MetadataList *mMetadataList;
+ ASTMetadataHLSL *mMetadata;
+ size_t mIndex;
+ const CallDAG &mDag;
+
+ // Contains a stack of the control flow nodes that are parents of the node being
+ // currently visited. It is used to mark control flows using a gradient.
+ std::vector<TIntermNode*> mParents;
+};
+
+// Traverses the AST of a function definition to compute the the discontinuous loops
+// and the if statements containing gradient loops. It assumes that the gradient loops
+// (loops that contain a gradient) have already been computed and that it has already
+// traversed the current function's callees.
+class PullComputeDiscontinuousAndGradientLoops : public TIntermTraverser
+{
+ public:
+ PullComputeDiscontinuousAndGradientLoops(MetadataList *metadataList,
+ size_t index,
+ const CallDAG &dag)
+ : TIntermTraverser(true, false, true),
+ mMetadataList(metadataList),
+ mMetadata(&(*metadataList)[index]),
+ mIndex(index),
+ mDag(dag)
+ {
+ }
+
+ void traverse(TIntermAggregate *node)
+ {
+ node->traverse(this);
+ ASSERT(mLoopsAndSwitches.empty());
+ ASSERT(mIfs.empty());
+ }
+
+ // Called when traversing a gradient loop or a call to a function with a
+ // gradient loop in its call graph.
+ void onGradientLoop()
+ {
+ mMetadata->mHasGradientLoopInCallGraph = true;
+ // Mark the latest if as using a discontinuous loop.
+ if (!mIfs.empty())
+ {
+ mMetadata->mIfsContainingGradientLoop.insert(mIfs.back());
+ }
+ }
+
+ bool visitLoop(Visit visit, TIntermLoop *loop) override
+ {
+ if (visit == PreVisit)
+ {
+ mLoopsAndSwitches.push_back(loop);
+
+ if (mMetadata->hasGradientInCallGraph(loop))
+ {
+ onGradientLoop();
+ }
+ }
+ else if (visit == PostVisit)
+ {
+ ASSERT(mLoopsAndSwitches.back() == loop);
+ mLoopsAndSwitches.pop_back();
+ }
+
+ return true;
+ }
+
+ bool visitSelection(Visit visit, TIntermSelection *node) override
+ {
+ if (visit == PreVisit)
+ {
+ mIfs.push_back(node);
+ }
+ else if (visit == PostVisit)
+ {
+ ASSERT(mIfs.back() == node);
+ mIfs.pop_back();
+ // An if using a discontinuous loop means its parents ifs are also discontinuous.
+ if (mMetadata->mIfsContainingGradientLoop.count(node) > 0 && !mIfs.empty())
+ {
+ mMetadata->mIfsContainingGradientLoop.insert(mIfs.back());
+ }
+ }
+
+ return true;
+ }
+
+ bool visitBranch(Visit visit, TIntermBranch *node) override
+ {
+ if (visit == PreVisit)
+ {
+ switch (node->getFlowOp())
+ {
+ case EOpBreak:
+ {
+ ASSERT(!mLoopsAndSwitches.empty());
+ TIntermLoop *loop = mLoopsAndSwitches.back()->getAsLoopNode();
+ if (loop != nullptr)
+ {
+ mMetadata->mDiscontinuousLoops.insert(loop);
+ }
+ }
+ break;
+ case EOpContinue:
+ {
+ ASSERT(!mLoopsAndSwitches.empty());
+ TIntermLoop *loop = nullptr;
+ size_t i = mLoopsAndSwitches.size();
+ while (loop == nullptr && i > 0)
+ {
+ --i;
+ loop = mLoopsAndSwitches.at(i)->getAsLoopNode();
+ }
+ ASSERT(loop != nullptr);
+ mMetadata->mDiscontinuousLoops.insert(loop);
+ }
+ break;
+ case EOpKill:
+ case EOpReturn:
+ // A return or discard jumps out of all the enclosing loops
+ if (!mLoopsAndSwitches.empty())
+ {
+ for (TIntermNode *intermNode : mLoopsAndSwitches)
+ {
+ TIntermLoop *loop = intermNode->getAsLoopNode();
+ if (loop)
+ {
+ mMetadata->mDiscontinuousLoops.insert(loop);
+ }
+ }
+ }
+ break;
+ default:
+ UNREACHABLE();
+ }
+ }
+
+ return true;
+ }
+
+ bool visitAggregate(Visit visit, TIntermAggregate *node) override
+ {
+ if (visit == PreVisit && node->getOp() == EOpFunctionCall)
+ {
+ if (node->isUserDefined())
+ {
+ size_t calleeIndex = mDag.findIndex(node);
+ ASSERT(calleeIndex != CallDAG::InvalidIndex && calleeIndex < mIndex);
+ UNUSED_ASSERTION_VARIABLE(mIndex);
+
+ if ((*mMetadataList)[calleeIndex].mHasGradientLoopInCallGraph)
+ {
+ onGradientLoop();
+ }
+ }
+ }
+
+ return true;
+ }
+
+ bool visitSwitch(Visit visit, TIntermSwitch *node) override
+ {
+ if (visit == PreVisit)
+ {
+ mLoopsAndSwitches.push_back(node);
+ }
+ else if (visit == PostVisit)
+ {
+ ASSERT(mLoopsAndSwitches.back() == node);
+ mLoopsAndSwitches.pop_back();
+ }
+ return true;
+ }
+
+ private:
+ MetadataList *mMetadataList;
+ ASTMetadataHLSL *mMetadata;
+ size_t mIndex;
+ const CallDAG &mDag;
+
+ std::vector<TIntermNode*> mLoopsAndSwitches;
+ std::vector<TIntermSelection*> mIfs;
+};
+
+// Tags all the functions called in a discontinuous loop
+class PushDiscontinuousLoops : public TIntermTraverser
+{
+ public:
+ PushDiscontinuousLoops(MetadataList *metadataList, size_t index, const CallDAG &dag)
+ : TIntermTraverser(true, true, true),
+ mMetadataList(metadataList),
+ mMetadata(&(*metadataList)[index]),
+ mIndex(index),
+ mDag(dag),
+ mNestedDiscont(mMetadata->mCalledInDiscontinuousLoop ? 1 : 0)
+ {
+ }
+
+ void traverse(TIntermAggregate *node)
+ {
+ node->traverse(this);
+ ASSERT(mNestedDiscont == (mMetadata->mCalledInDiscontinuousLoop ? 1 : 0));
+ }
+
+ bool visitLoop(Visit visit, TIntermLoop *loop) override
+ {
+ bool isDiscontinuous = mMetadata->mDiscontinuousLoops.count(loop) > 0;
+
+ if (visit == PreVisit && isDiscontinuous)
+ {
+ mNestedDiscont++;
+ }
+ else if (visit == PostVisit && isDiscontinuous)
+ {
+ mNestedDiscont--;
+ }
+
+ return true;
+ }
+
+ bool visitAggregate(Visit visit, TIntermAggregate *node) override
+ {
+ switch (node->getOp())
+ {
+ case EOpFunctionCall:
+ if (visit == PreVisit && node->isUserDefined() && mNestedDiscont > 0)
+ {
+ size_t calleeIndex = mDag.findIndex(node);
+ ASSERT(calleeIndex != CallDAG::InvalidIndex && calleeIndex < mIndex);
+ UNUSED_ASSERTION_VARIABLE(mIndex);
+
+ (*mMetadataList)[calleeIndex].mCalledInDiscontinuousLoop = true;
+ }
+ break;
+ default:
+ break;
+ }
+ return true;
+ }
+
+ private:
+ MetadataList *mMetadataList;
+ ASTMetadataHLSL *mMetadata;
+ size_t mIndex;
+ const CallDAG &mDag;
+
+ int mNestedDiscont;
+};
+
+}
+
+bool ASTMetadataHLSL::hasGradientInCallGraph(TIntermLoop *node)
+{
+ return mControlFlowsContainingGradient.count(node) > 0;
+}
+
+bool ASTMetadataHLSL::hasGradientLoop(TIntermSelection *node)
+{
+ return mIfsContainingGradientLoop.count(node) > 0;
+}
+
+MetadataList CreateASTMetadataHLSL(TIntermNode *root, const CallDAG &callDag)
+{
+ MetadataList metadataList(callDag.size());
+
+ // Compute all the information related to when gradient operations are used.
+ // We want to know for each function and control flow operation if they have
+ // a gradient operation in their call graph (shortened to "using a gradient"
+ // in the rest of the file).
+ //
+ // This computation is logically split in three steps:
+ // 1 - For each function compute if it uses a gradient in its body, ignoring
+ // calls to other user-defined functions.
+ // 2 - For each function determine if it uses a gradient in its call graph,
+ // using the result of step 1 and the CallDAG to know its callees.
+ // 3 - For each control flow statement of each function, check if it uses a
+ // gradient in the function's body, or if it calls a user-defined function that
+ // uses a gradient.
+ //
+ // We take advantage of the call graph being a DAG and instead compute 1, 2 and 3
+ // for leaves first, then going down the tree. This is correct because 1 doesn't
+ // depend on other functions, and 2 and 3 depend only on callees.
+ for (size_t i = 0; i < callDag.size(); i++)
+ {
+ PullGradient pull(&metadataList, i, callDag);
+ pull.traverse(callDag.getRecordFromIndex(i).node);
+ }
+
+ // Compute which loops are discontinuous and which function are called in
+ // these loops. The same way computing gradient usage is a "pull" process,
+ // computing "bing used in a discont. loop" is a push process. However we also
+ // need to know what ifs have a discontinuous loop inside so we do the same type
+ // of callgraph analysis as for the gradient.
+
+ // First compute which loops are discontinuous (no specific order) and pull
+ // the ifs and functions using a gradient loop.
+ for (size_t i = 0; i < callDag.size(); i++)
+ {
+ PullComputeDiscontinuousAndGradientLoops pull(&metadataList, i, callDag);
+ pull.traverse(callDag.getRecordFromIndex(i).node);
+ }
+
+ // Then push the information to callees, either from the a local discontinuous
+ // loop or from the caller being called in a discontinuous loop already
+ for (size_t i = callDag.size(); i-- > 0;)
+ {
+ PushDiscontinuousLoops push(&metadataList, i, callDag);
+ push.traverse(callDag.getRecordFromIndex(i).node);
+ }
+
+ // We create "Lod0" version of functions with the gradient operations replaced
+ // by non-gradient operations so that the D3D compiler is happier with discont
+ // loops.
+ for (auto &metadata : metadataList)
+ {
+ metadata.mNeedsLod0 = metadata.mCalledInDiscontinuousLoop && metadata.mUsesGradient;
+ }
+
+ return metadataList;
+}
diff --git a/src/3rdparty/angle/src/compiler/translator/ASTMetadataHLSL.h b/src/3rdparty/angle/src/compiler/translator/ASTMetadataHLSL.h
new file mode 100644
index 0000000000..39e671e3e0
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/translator/ASTMetadataHLSL.h
@@ -0,0 +1,58 @@
+//
+// 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.
+//
+
+// Defines analyses of the AST needed for HLSL generation
+
+#ifndef COMPILER_TRANSLATOR_ASTMETADATAHLSL_H_
+#define COMPILER_TRANSLATOR_ASTMETADATAHLSL_H_
+
+#include <set>
+#include <vector>
+
+class CallDAG;
+class TIntermNode;
+class TIntermSelection;
+class TIntermLoop;
+
+struct ASTMetadataHLSL
+{
+ ASTMetadataHLSL()
+ : mUsesGradient(false),
+ mCalledInDiscontinuousLoop(false),
+ mHasGradientLoopInCallGraph(false),
+ mNeedsLod0(false)
+ {
+ }
+
+ // Here "something uses a gradient" means here that it either contains a
+ // gradient operation, or a call to a function that uses a gradient.
+ bool hasGradientInCallGraph(TIntermLoop *node);
+ bool hasGradientLoop(TIntermSelection *node);
+
+ // Does the function use a gradient.
+ bool mUsesGradient;
+
+ // Even if usesGradient is true, some control flow might not use a gradient
+ // so we store the set of all gradient-using control flows.
+ std::set<TIntermNode*> mControlFlowsContainingGradient;
+
+ // Remember information about the discontinuous loops and which functions
+ // are called in such loops.
+ bool mCalledInDiscontinuousLoop;
+ bool mHasGradientLoopInCallGraph;
+ std::set<TIntermLoop*> mDiscontinuousLoops;
+ std::set<TIntermSelection *> mIfsContainingGradientLoop;
+
+ // Will we need to generate a Lod0 version of the function.
+ bool mNeedsLod0;
+};
+
+typedef std::vector<ASTMetadataHLSL> MetadataList;
+
+// Return the AST analysis result, in the order defined by the call DAG
+MetadataList CreateASTMetadataHLSL(TIntermNode *root, const CallDAG &callDag);
+
+#endif // COMPILER_TRANSLATOR_ASTMETADATAHLSL_H_
diff --git a/src/3rdparty/angle/src/compiler/translator/ArrayReturnValueToOutParameter.cpp b/src/3rdparty/angle/src/compiler/translator/ArrayReturnValueToOutParameter.cpp
new file mode 100644
index 0000000000..510ade84c1
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/translator/ArrayReturnValueToOutParameter.cpp
@@ -0,0 +1,206 @@
+//
+// 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.
+//
+// The ArrayReturnValueToOutParameter function changes return values of an array type to out parameters in
+// function definitions, prototypes, and call sites.
+
+#include "compiler/translator/ArrayReturnValueToOutParameter.h"
+
+#include "compiler/translator/IntermNode.h"
+
+namespace
+{
+
+void CopyAggregateChildren(TIntermAggregate *from, TIntermAggregate *to)
+{
+ const TIntermSequence *fromSequence = from->getSequence();
+ for (size_t ii = 0; ii < fromSequence->size(); ++ii)
+ {
+ to->getSequence()->push_back(fromSequence->at(ii));
+ }
+}
+
+TIntermSymbol *CreateReturnValueSymbol(const TType &type)
+{
+ TIntermSymbol *node = new TIntermSymbol(0, "angle_return", type);
+ node->setInternal(true);
+ return node;
+}
+
+TIntermSymbol *CreateReturnValueOutSymbol(const TType &type)
+{
+ TType outType(type);
+ outType.setQualifier(EvqOut);
+ return CreateReturnValueSymbol(outType);
+}
+
+TIntermAggregate *CreateReplacementCall(TIntermAggregate *originalCall, TIntermTyped *returnValueTarget)
+{
+ TIntermAggregate *replacementCall = new TIntermAggregate(EOpFunctionCall);
+ replacementCall->setType(TType(EbtVoid));
+ replacementCall->setUserDefined();
+ replacementCall->setNameObj(originalCall->getNameObj());
+ replacementCall->setFunctionId(originalCall->getFunctionId());
+ replacementCall->setLine(originalCall->getLine());
+ TIntermSequence *replacementParameters = replacementCall->getSequence();
+ TIntermSequence *originalParameters = originalCall->getSequence();
+ for (auto &param : *originalParameters)
+ {
+ replacementParameters->push_back(param);
+ }
+ replacementParameters->push_back(returnValueTarget);
+ return replacementCall;
+}
+
+class ArrayReturnValueToOutParameterTraverser : private TIntermTraverser
+{
+ public:
+ static void apply(TIntermNode *root, unsigned int *temporaryIndex);
+ private:
+ ArrayReturnValueToOutParameterTraverser();
+
+ bool visitAggregate(Visit visit, TIntermAggregate *node) override;
+ bool visitBranch(Visit visit, TIntermBranch *node) override;
+ bool visitBinary(Visit visit, TIntermBinary *node) override;
+
+ bool mInFunctionWithArrayReturnValue;
+};
+
+void ArrayReturnValueToOutParameterTraverser::apply(TIntermNode *root, unsigned int *temporaryIndex)
+{
+ ArrayReturnValueToOutParameterTraverser arrayReturnValueToOutParam;
+ arrayReturnValueToOutParam.useTemporaryIndex(temporaryIndex);
+ root->traverse(&arrayReturnValueToOutParam);
+ arrayReturnValueToOutParam.updateTree();
+}
+
+ArrayReturnValueToOutParameterTraverser::ArrayReturnValueToOutParameterTraverser()
+ : TIntermTraverser(true, false, true),
+ mInFunctionWithArrayReturnValue(false)
+{
+}
+
+bool ArrayReturnValueToOutParameterTraverser::visitAggregate(Visit visit, TIntermAggregate *node)
+{
+ if (visit == PreVisit)
+ {
+ if (node->isArray())
+ {
+ if (node->getOp() == EOpFunction)
+ {
+ // Replace the parameters child node of the function definition with another node
+ // that has the out parameter added.
+ // Also set the function to return void.
+
+ TIntermAggregate *params = node->getSequence()->front()->getAsAggregate();
+ ASSERT(params != nullptr && params->getOp() == EOpParameters);
+
+ TIntermAggregate *replacementParams = new TIntermAggregate;
+ replacementParams->setOp(EOpParameters);
+ CopyAggregateChildren(params, replacementParams);
+ replacementParams->getSequence()->push_back(CreateReturnValueOutSymbol(node->getType()));
+ replacementParams->setLine(params->getLine());
+
+ mReplacements.push_back(NodeUpdateEntry(node, params, replacementParams, false));
+
+ node->setType(TType(EbtVoid));
+
+ mInFunctionWithArrayReturnValue = true;
+ }
+ else if (node->getOp() == EOpPrototype)
+ {
+ // Replace the whole prototype node with another node that has the out parameter added.
+ TIntermAggregate *replacement = new TIntermAggregate;
+ replacement->setOp(EOpPrototype);
+ CopyAggregateChildren(node, replacement);
+ replacement->getSequence()->push_back(CreateReturnValueOutSymbol(node->getType()));
+ replacement->setUserDefined();
+ replacement->setNameObj(node->getNameObj());
+ replacement->setFunctionId(node->getFunctionId());
+ replacement->setLine(node->getLine());
+ replacement->setType(TType(EbtVoid));
+
+ mReplacements.push_back(NodeUpdateEntry(getParentNode(), node, replacement, false));
+ }
+ else if (node->getOp() == EOpFunctionCall)
+ {
+ // Handle call sites where the returned array is not assigned.
+ // Examples where f() is a function returning an array:
+ // 1. f();
+ // 2. another_array == f();
+ // 3. another_function(f());
+ // 4. return f();
+ // Cases 2 to 4 are already converted to simpler cases by SeparateExpressionsReturningArrays, so we
+ // only need to worry about the case where a function call returning an array forms an expression by
+ // itself.
+ TIntermAggregate *parentAgg = getParentNode()->getAsAggregate();
+ if (parentAgg != nullptr && parentAgg->getOp() == EOpSequence)
+ {
+ nextTemporaryIndex();
+ TIntermSequence replacements;
+ replacements.push_back(createTempDeclaration(node->getType()));
+ TIntermSymbol *returnSymbol = createTempSymbol(node->getType());
+ replacements.push_back(CreateReplacementCall(node, returnSymbol));
+ mMultiReplacements.push_back(NodeReplaceWithMultipleEntry(parentAgg, node, replacements));
+ }
+ return false;
+ }
+ }
+ }
+ else if (visit == PostVisit)
+ {
+ if (node->getOp() == EOpFunction)
+ {
+ mInFunctionWithArrayReturnValue = false;
+ }
+ }
+ return true;
+}
+
+bool ArrayReturnValueToOutParameterTraverser::visitBranch(Visit visit, TIntermBranch *node)
+{
+ if (mInFunctionWithArrayReturnValue && node->getFlowOp() == EOpReturn)
+ {
+ // Instead of returning a value, assign to the out parameter and then return.
+ TIntermSequence replacements;
+
+ TIntermBinary *replacementAssignment = new TIntermBinary(EOpAssign);
+ TIntermTyped *expression = node->getExpression();
+ ASSERT(expression != nullptr);
+ replacementAssignment->setLeft(CreateReturnValueSymbol(expression->getType()));
+ replacementAssignment->setRight(node->getExpression());
+ replacementAssignment->setType(expression->getType());
+ replacementAssignment->setLine(expression->getLine());
+ replacements.push_back(replacementAssignment);
+
+ TIntermBranch *replacementBranch = new TIntermBranch(EOpReturn, nullptr);
+ replacementBranch->setLine(node->getLine());
+ replacements.push_back(replacementBranch);
+
+ mMultiReplacements.push_back(NodeReplaceWithMultipleEntry(getParentNode()->getAsAggregate(), node, replacements));
+ }
+ return false;
+}
+
+bool ArrayReturnValueToOutParameterTraverser::visitBinary(Visit visit, TIntermBinary *node)
+{
+ if (node->getOp() == EOpAssign && node->getLeft()->isArray())
+ {
+ TIntermAggregate *rightAgg = node->getRight()->getAsAggregate();
+ if (rightAgg != nullptr && rightAgg->getOp() == EOpFunctionCall && rightAgg->isUserDefined())
+ {
+ TIntermAggregate *replacementCall = CreateReplacementCall(rightAgg, node->getLeft());
+ mReplacements.push_back(NodeUpdateEntry(getParentNode(), node, replacementCall, false));
+ }
+ }
+ return false;
+}
+
+} // namespace
+
+void ArrayReturnValueToOutParameter(TIntermNode *root, unsigned int *temporaryIndex)
+{
+ ArrayReturnValueToOutParameterTraverser::apply(root, temporaryIndex);
+}
diff --git a/src/3rdparty/angle/src/compiler/translator/ArrayReturnValueToOutParameter.h b/src/3rdparty/angle/src/compiler/translator/ArrayReturnValueToOutParameter.h
new file mode 100644
index 0000000000..983e203e62
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/translator/ArrayReturnValueToOutParameter.h
@@ -0,0 +1,16 @@
+//
+// 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.
+//
+// The ArrayReturnValueToOutParameter function changes return values of an array type to out parameters in
+// function definitions, prototypes and call sites.
+
+#ifndef COMPILER_TRANSLATOR_ARRAYRETURNVALUETOOUTPARAMETER_H_
+#define COMPILER_TRANSLATOR_ARRAYRETURNVALUETOOUTPARAMETER_H_
+
+class TIntermNode;
+
+void ArrayReturnValueToOutParameter(TIntermNode *root, unsigned int *temporaryIndex);
+
+#endif // COMPILER_TRANSLATOR_ARRAYRETURNVALUETOOUTPARAMETER_H_
diff --git a/src/3rdparty/angle/src/compiler/translator/BaseTypes.h b/src/3rdparty/angle/src/compiler/translator/BaseTypes.h
index ee1428b2d3..0ed6d0e62f 100644
--- a/src/3rdparty/angle/src/compiler/translator/BaseTypes.h
+++ b/src/3rdparty/angle/src/compiler/translator/BaseTypes.h
@@ -7,7 +7,7 @@
#ifndef COMPILER_TRANSLATOR_BASETYPES_H_
#define COMPILER_TRANSLATOR_BASETYPES_H_
-#include "compiler/translator/compilerdebug.h"
+#include "common/debug.h"
//
// Precision qualifiers
@@ -18,7 +18,10 @@ enum TPrecision
EbpUndefined,
EbpLow,
EbpMedium,
- EbpHigh
+ EbpHigh,
+
+ // end of list
+ EbpLast
};
inline const char* getPrecisionString(TPrecision p)
@@ -77,6 +80,9 @@ enum TBasicType
EbtStruct,
EbtInterfaceBlock,
EbtAddress, // should be deprecated??
+
+ // end of list
+ EbtLast
};
const char* getBasicString(TBasicType t);
@@ -284,21 +290,18 @@ inline bool SupportsPrecision(TBasicType type)
//
enum TQualifier
{
- EvqTemporary, // For temporaries (within a function), read/write
- EvqGlobal, // For globals read/write
- EvqInternal, // For internal use, not visible to the user
- EvqConst, // User defined constants and non-output parameters in functions
- EvqAttribute, // Readonly
- EvqVaryingIn, // readonly, fragment shaders only
- EvqVaryingOut, // vertex shaders only read/write
- EvqInvariantVaryingIn, // readonly, fragment shaders only
- EvqInvariantVaryingOut, // vertex shaders only read/write
- EvqUniform, // Readonly, vertex and fragment
-
- EvqVertexIn, // Vertex shader input
- EvqFragmentOut, // Fragment shader output
- EvqVertexOut, // Vertex shader output
- EvqFragmentIn, // Fragment shader input
+ EvqTemporary, // For temporaries (within a function), read/write
+ EvqGlobal, // For globals read/write
+ EvqConst, // User defined constants and non-output parameters in functions
+ EvqAttribute, // Readonly
+ EvqVaryingIn, // readonly, fragment shaders only
+ EvqVaryingOut, // vertex shaders only read/write
+ EvqUniform, // Readonly, vertex and fragment
+
+ EvqVertexIn, // Vertex shader input
+ EvqFragmentOut, // Fragment shader output
+ EvqVertexOut, // Vertex shader output
+ EvqFragmentIn, // Fragment shader input
// parameters
EvqIn,
@@ -321,21 +324,26 @@ enum TQualifier
// built-ins written by fragment shader
EvqFragColor,
EvqFragData,
- EvqFragDepth,
+
+ EvqFragDepth, // gl_FragDepth for ESSL300.
+ EvqFragDepthEXT, // gl_FragDepthEXT for ESSL100, EXT_frag_depth.
+
+ EvqSecondaryFragColorEXT, // EXT_blend_func_extended
+ EvqSecondaryFragDataEXT, // EXT_blend_func_extended
// 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
+ EvqSmooth, // Incomplete qualifier, smooth is the default
+ EvqFlat, // Incomplete qualifier
EvqSmoothOut = EvqSmooth,
- EvqFlatOut = EvqFlat,
- EvqCentroidOut, // Implies smooth
+ EvqFlatOut = EvqFlat,
+ EvqCentroidOut, // Implies smooth
EvqSmoothIn,
EvqFlatIn,
- EvqCentroidIn, // Implies smooth
+ EvqCentroidIn, // Implies smooth
// end of list
EvqLast
@@ -384,43 +392,47 @@ struct TLayoutQualifier
//
inline const char* getQualifierString(TQualifier q)
{
+ // clang-format off
switch(q)
{
- case EvqTemporary: return "Temporary"; break;
- case EvqGlobal: return "Global"; break;
- case EvqConst: return "const"; break;
- case EvqConstReadOnly: return "const"; break;
- case EvqAttribute: return "attribute"; break;
- case EvqVaryingIn: return "varying"; break;
- case EvqVaryingOut: return "varying"; break;
- case EvqInvariantVaryingIn: return "invariant varying"; break;
- case EvqInvariantVaryingOut:return "invariant varying"; break;
- case EvqUniform: return "uniform"; break;
- case EvqVertexIn: return "in"; break;
- case EvqFragmentOut: return "out"; break;
- case EvqVertexOut: return "out"; break;
- case EvqFragmentIn: return "in"; break;
- case EvqIn: return "in"; break;
- case EvqOut: return "out"; break;
- case EvqInOut: return "inout"; break;
- case EvqInstanceID: return "InstanceID"; break;
- case EvqPosition: return "Position"; break;
- case EvqPointSize: return "PointSize"; break;
- case EvqFragCoord: return "FragCoord"; break;
- case EvqFrontFacing: return "FrontFacing"; break;
- case EvqFragColor: return "FragColor"; break;
- case EvqFragData: return "FragData"; break;
- case EvqFragDepth: return "FragDepth"; break;
- case EvqSmoothOut: return "smooth out"; break;
- case EvqCentroidOut: return "centroid out"; break;
- case EvqFlatOut: return "flat out"; break;
- case EvqSmoothIn: return "smooth in"; break;
- case EvqCentroidIn: return "centroid in"; break;
- case EvqFlatIn: return "flat in"; break;
- case EvqLastFragColor: return "LastFragColor"; break;
- case EvqLastFragData: return "LastFragData"; break;
- default: UNREACHABLE(); return "unknown qualifier";
+ case EvqTemporary: return "Temporary";
+ case EvqGlobal: return "Global";
+ case EvqConst: return "const";
+ case EvqAttribute: return "attribute";
+ case EvqVaryingIn: return "varying";
+ case EvqVaryingOut: return "varying";
+ case EvqUniform: return "uniform";
+ case EvqVertexIn: return "in";
+ case EvqFragmentOut: return "out";
+ case EvqVertexOut: return "out";
+ case EvqFragmentIn: return "in";
+ case EvqIn: return "in";
+ case EvqOut: return "out";
+ case EvqInOut: return "inout";
+ case EvqConstReadOnly: return "const";
+ case EvqInstanceID: return "InstanceID";
+ case EvqPosition: return "Position";
+ case EvqPointSize: return "PointSize";
+ case EvqFragCoord: return "FragCoord";
+ case EvqFrontFacing: return "FrontFacing";
+ case EvqPointCoord: return "PointCoord";
+ case EvqFragColor: return "FragColor";
+ case EvqFragData: return "FragData";
+ case EvqFragDepthEXT: return "FragDepth";
+ case EvqFragDepth: return "FragDepth";
+ case EvqSecondaryFragColorEXT: return "SecondaryFragColorEXT";
+ case EvqSecondaryFragDataEXT: return "SecondaryFragDataEXT";
+ case EvqLastFragColor: return "LastFragColor";
+ case EvqLastFragData: return "LastFragData";
+ case EvqSmoothOut: return "smooth out";
+ case EvqCentroidOut: return "centroid out";
+ case EvqFlatOut: return "flat out";
+ case EvqSmoothIn: return "smooth in";
+ case EvqFlatIn: return "flat in";
+ case EvqCentroidIn: return "centroid in";
+ default: UNREACHABLE(); return "unknown qualifier";
}
+ // clang-format on
}
inline const char* getMatrixPackingString(TLayoutMatrixPacking mpq)
diff --git a/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulator.cpp b/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulator.cpp
index 51461207c5..0c7f149ee6 100644
--- a/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulator.cpp
+++ b/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulator.cpp
@@ -11,28 +11,31 @@
class BuiltInFunctionEmulator::BuiltInFunctionEmulationMarker : public TIntermTraverser
{
public:
- BuiltInFunctionEmulationMarker(BuiltInFunctionEmulator& emulator)
- : mEmulator(emulator)
+ BuiltInFunctionEmulationMarker(BuiltInFunctionEmulator &emulator)
+ : TIntermTraverser(true, false, false),
+ mEmulator(emulator)
{
}
- virtual bool visitUnary(Visit visit, TIntermUnary* node)
+ bool visitUnary(Visit visit, TIntermUnary *node) override
{
- if (visit == PreVisit) {
- bool needToEmulate = mEmulator.SetFunctionCalled(
- node->getOp(), node->getOperand()->getType());
+ if (visit == PreVisit)
+ {
+ bool needToEmulate = mEmulator.SetFunctionCalled(node->getOp(), node->getOperand()->getType());
if (needToEmulate)
node->setUseEmulatedFunction();
}
return true;
}
- virtual bool visitAggregate(Visit visit, TIntermAggregate* node)
+ bool visitAggregate(Visit visit, TIntermAggregate *node) override
{
- if (visit == PreVisit) {
+ if (visit == PreVisit)
+ {
// Here we handle all the built-in functions instead of the ones we
// currently identified as problematic.
- switch (node->getOp()) {
+ switch (node->getOp())
+ {
case EOpLessThan:
case EOpGreaterThan:
case EOpLessThanEqual:
@@ -59,14 +62,14 @@ class BuiltInFunctionEmulator::BuiltInFunctionEmulationMarker : public TIntermTr
break;
default:
return true;
- };
- const TIntermSequence& sequence = *(node->getSequence());
+ }
+ const TIntermSequence &sequence = *(node->getSequence());
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();
+ TIntermTyped *param1 = sequence[0]->getAsTyped();
+ TIntermTyped *param2 = sequence[1]->getAsTyped();
if (!param1 || !param2)
return true;
needToEmulate = mEmulator.SetFunctionCalled(
@@ -74,9 +77,9 @@ class BuiltInFunctionEmulator::BuiltInFunctionEmulationMarker : public TIntermTr
}
else if (sequence.size() == 3)
{
- TIntermTyped* param1 = sequence[0]->getAsTyped();
- TIntermTyped* param2 = sequence[1]->getAsTyped();
- TIntermTyped* param3 = sequence[2]->getAsTyped();
+ TIntermTyped *param1 = sequence[0]->getAsTyped();
+ TIntermTyped *param2 = sequence[1]->getAsTyped();
+ TIntermTyped *param3 = sequence[2]->getAsTyped();
if (!param1 || !param2 || !param3)
return true;
needToEmulate = mEmulator.SetFunctionCalled(
@@ -94,34 +97,28 @@ class BuiltInFunctionEmulator::BuiltInFunctionEmulationMarker : public TIntermTr
}
private:
- BuiltInFunctionEmulator& mEmulator;
+ BuiltInFunctionEmulator &mEmulator;
};
BuiltInFunctionEmulator::BuiltInFunctionEmulator()
{}
-void BuiltInFunctionEmulator::addEmulatedFunction(
- TOperator op, const TType& param,
- const char* emulatedFunctionDefinition)
+void BuiltInFunctionEmulator::addEmulatedFunction(TOperator op, const TType *param,
+ const char *emulatedFunctionDefinition)
{
- mEmulatedFunctions[FunctionId(op, param)] =
- std::string(emulatedFunctionDefinition);
+ mEmulatedFunctions[FunctionId(op, param)] = std::string(emulatedFunctionDefinition);
}
-void BuiltInFunctionEmulator::addEmulatedFunction(
- TOperator op, const TType& param1, const TType& param2,
- const char* emulatedFunctionDefinition)
+void BuiltInFunctionEmulator::addEmulatedFunction(TOperator op, const TType *param1, const TType *param2,
+ const char *emulatedFunctionDefinition)
{
- mEmulatedFunctions[FunctionId(op, param1, param2)] =
- std::string(emulatedFunctionDefinition);
+ mEmulatedFunctions[FunctionId(op, param1, param2)] = std::string(emulatedFunctionDefinition);
}
-void BuiltInFunctionEmulator::addEmulatedFunction(
- TOperator op, const TType& param1, const TType& param2, const TType& param3,
- const char* emulatedFunctionDefinition)
+void BuiltInFunctionEmulator::addEmulatedFunction(TOperator op, const TType *param1, const TType *param2,
+ const TType *param3, const char *emulatedFunctionDefinition)
{
- mEmulatedFunctions[FunctionId(op, param1, param2, param3)] =
- std::string(emulatedFunctionDefinition);
+ mEmulatedFunctions[FunctionId(op, param1, param2, param3)] = std::string(emulatedFunctionDefinition);
}
bool BuiltInFunctionEmulator::IsOutputEmpty() const
@@ -129,48 +126,48 @@ bool BuiltInFunctionEmulator::IsOutputEmpty() const
return (mFunctions.size() == 0);
}
-void BuiltInFunctionEmulator::OutputEmulatedFunctions(
- TInfoSinkBase& out) const
+void BuiltInFunctionEmulator::OutputEmulatedFunctions(TInfoSinkBase &out) const
{
- for (size_t i = 0; i < mFunctions.size(); ++i) {
+ for (size_t i = 0; i < mFunctions.size(); ++i)
+ {
out << mEmulatedFunctions.find(mFunctions[i])->second << "\n\n";
}
}
-bool BuiltInFunctionEmulator::SetFunctionCalled(
- TOperator op, const TType& param)
+bool BuiltInFunctionEmulator::SetFunctionCalled(TOperator op, const TType &param)
{
- return SetFunctionCalled(FunctionId(op, param));
+ return SetFunctionCalled(FunctionId(op, &param));
}
-bool BuiltInFunctionEmulator::SetFunctionCalled(
- TOperator op, const TType& param1, const TType& param2)
+bool BuiltInFunctionEmulator::SetFunctionCalled(TOperator op, const TType &param1, const TType &param2)
{
- return SetFunctionCalled(FunctionId(op, param1, param2));
+ return SetFunctionCalled(FunctionId(op, &param1, &param2));
}
-bool BuiltInFunctionEmulator::SetFunctionCalled(
- TOperator op, const TType& param1, const TType& param2, const TType& param3)
+bool BuiltInFunctionEmulator::SetFunctionCalled(TOperator op,
+ const TType &param1, const TType &param2, const TType &param3)
{
- return SetFunctionCalled(FunctionId(op, param1, param2, param3));
+ return SetFunctionCalled(FunctionId(op, &param1, &param2, &param3));
}
-bool BuiltInFunctionEmulator::SetFunctionCalled(
- const FunctionId& functionId) {
+bool BuiltInFunctionEmulator::SetFunctionCalled(const FunctionId &functionId)
+{
if (mEmulatedFunctions.find(functionId) != mEmulatedFunctions.end())
{
- for (size_t i = 0; i < mFunctions.size(); ++i) {
+ for (size_t i = 0; i < mFunctions.size(); ++i)
+ {
if (mFunctions[i] == functionId)
return true;
}
- mFunctions.push_back(functionId);
+ // Copy the functionId if it needs to be stored, to make sure that the TType pointers inside
+ // remain valid and constant.
+ mFunctions.push_back(functionId.getCopy());
return true;
}
return false;
}
-void BuiltInFunctionEmulator::MarkBuiltInFunctionsForEmulation(
- TIntermNode* root)
+void BuiltInFunctionEmulator::MarkBuiltInFunctionsForEmulation(TIntermNode *root)
{
ASSERT(root);
@@ -188,32 +185,30 @@ void BuiltInFunctionEmulator::Cleanup()
//static
TString BuiltInFunctionEmulator::GetEmulatedFunctionName(
- const TString& name)
+ const TString &name)
{
ASSERT(name[name.length() - 1] == '(');
return "webgl_" + name.substr(0, name.length() - 1) + "_emu(";
}
-BuiltInFunctionEmulator::FunctionId::FunctionId
- (TOperator op, const TType& param)
+BuiltInFunctionEmulator::FunctionId::FunctionId(TOperator op, const TType *param)
: mOp(op),
mParam1(param),
- mParam2(EbtVoid),
- mParam3(EbtVoid)
+ mParam2(new TType(EbtVoid)),
+ mParam3(new TType(EbtVoid))
{
}
-BuiltInFunctionEmulator::FunctionId::FunctionId
- (TOperator op, const TType& param1, const TType& param2)
+BuiltInFunctionEmulator::FunctionId::FunctionId(TOperator op, const TType *param1, const TType *param2)
: mOp(op),
mParam1(param1),
mParam2(param2),
- mParam3(EbtVoid)
+ mParam3(new TType(EbtVoid))
{
}
-BuiltInFunctionEmulator::FunctionId::FunctionId
- (TOperator op, const TType& param1, const TType& param2, const TType& param3)
+BuiltInFunctionEmulator::FunctionId::FunctionId(TOperator op,
+ const TType *param1, const TType *param2, const TType *param3)
: mOp(op),
mParam1(param1),
mParam2(param2),
@@ -221,25 +216,28 @@ BuiltInFunctionEmulator::FunctionId::FunctionId
{
}
-bool BuiltInFunctionEmulator::FunctionId::operator==
- (const BuiltInFunctionEmulator::FunctionId& other) const
+bool BuiltInFunctionEmulator::FunctionId::operator==(const BuiltInFunctionEmulator::FunctionId &other) const
{
return (mOp == other.mOp &&
- mParam1 == other.mParam1 &&
- mParam2 == other.mParam2 &&
- mParam3 == other.mParam3);
+ *mParam1 == *other.mParam1 &&
+ *mParam2 == *other.mParam2 &&
+ *mParam3 == *other.mParam3);
}
-bool BuiltInFunctionEmulator::FunctionId::operator<
- (const BuiltInFunctionEmulator::FunctionId& other) const
+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;
+ 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
}
+
+BuiltInFunctionEmulator::FunctionId BuiltInFunctionEmulator::FunctionId::getCopy() const
+{
+ return FunctionId(mOp, new TType(*mParam1), new TType(*mParam2), new TType(*mParam3));
+}
diff --git a/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulator.h b/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulator.h
index df556985e1..6976edfd57 100644
--- a/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulator.h
+++ b/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulator.h
@@ -21,23 +21,25 @@ class BuiltInFunctionEmulator
public:
BuiltInFunctionEmulator();
- void MarkBuiltInFunctionsForEmulation(TIntermNode* root);
+ void MarkBuiltInFunctionsForEmulation(TIntermNode *root);
void Cleanup();
// "name(" becomes "webgl_name_emu(".
- static TString GetEmulatedFunctionName(const TString& name);
+ static TString GetEmulatedFunctionName(const TString &name);
bool IsOutputEmpty() const;
// Output function emulation definition. This should be before any other
// shader source.
- void OutputEmulatedFunctions(TInfoSinkBase& out) const;
+ 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);
+ 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);
private:
class BuiltInFunctionEmulationMarker;
@@ -46,28 +48,32 @@ class BuiltInFunctionEmulator
// 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);
+ 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);
+ 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;
+ bool operator==(const FunctionId &other) const;
+ bool operator<(const FunctionId &other) const;
+
+ FunctionId getCopy() const;
private:
TOperator mOp;
- TType mParam1;
- TType mParam2;
- TType mParam3;
+
+ // The memory that these TType objects use is freed by PoolAllocator. The BuiltInFunctionEmulator's lifetime
+ // can extend until after the memory pool is freed, but that's not an issue since this class never destructs
+ // these objects.
+ const TType *mParam1;
+ const TType *mParam2;
+ const TType *mParam3;
};
- bool SetFunctionCalled(const FunctionId& functionId);
+ bool SetFunctionCalled(const FunctionId &functionId);
// Map from function id to emulated function definition
std::map<FunctionId, std::string> mEmulatedFunctions;
diff --git a/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulatorGLSL.cpp b/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulatorGLSL.cpp
index 9de99831ad..098560d110 100644
--- a/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulatorGLSL.cpp
+++ b/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulatorGLSL.cpp
@@ -7,9 +7,11 @@
#include "angle_gl.h"
#include "compiler/translator/BuiltInFunctionEmulator.h"
#include "compiler/translator/BuiltInFunctionEmulatorGLSL.h"
+#include "compiler/translator/Cache.h"
#include "compiler/translator/SymbolTable.h"
+#include "compiler/translator/VersionGLSL.h"
-void InitBuiltInFunctionEmulatorForGLSL(BuiltInFunctionEmulator *emu, sh::GLenum shaderType)
+void InitBuiltInFunctionEmulatorForGLSLWorkarounds(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
@@ -17,10 +19,10 @@ void InitBuiltInFunctionEmulatorForGLSL(BuiltInFunctionEmulator *emu, sh::GLenum
// 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);
+ const TType *float1 = TCache::getType(EbtFloat);
+ const TType *float2 = TCache::getType(EbtFloat, 2);
+ const TType *float3 = TCache::getType(EbtFloat, 3);
+ const TType *float4 = TCache::getType(EbtFloat, 4);
if (shaderType == GL_FRAGMENT_SHADER)
{
@@ -35,3 +37,153 @@ void InitBuiltInFunctionEmulatorForGLSL(BuiltInFunctionEmulator *emu, sh::GLenum
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))");
}
+
+// Emulate built-in functions missing from GLSL 1.30 and higher
+void InitBuiltInFunctionEmulatorForGLSLMissingFunctions(BuiltInFunctionEmulator *emu, sh::GLenum shaderType,
+ int targetGLSLVersion)
+{
+ // Emulate packSnorm2x16, packHalf2x16, unpackSnorm2x16, and unpackHalf2x16 (GLSL 4.20)
+ // by using floatBitsToInt, floatBitsToUint, intBitsToFloat, and uintBitsToFloat (GLSL 3.30).
+ if (targetGLSLVersion >= GLSL_VERSION_330 && targetGLSLVersion < GLSL_VERSION_420)
+ {
+ const TType *float2 = TCache::getType(EbtFloat, 2);
+ const TType *uint1 = TCache::getType(EbtUInt);
+
+ // clang-format off
+ emu->addEmulatedFunction(EOpPackSnorm2x16, float2,
+ "uint webgl_packSnorm2x16_emu(vec2 v)\n"
+ "{\n"
+ " #if defined(GL_ARB_shading_language_packing)\n"
+ " return packSnorm2x16(v);\n"
+ " #else\n"
+ " int x = int(round(clamp(v.x, -1.0, 1.0) * 32767.0));\n"
+ " int y = int(round(clamp(v.y, -1.0, 1.0) * 32767.0));\n"
+ " return uint((y << 16) | (x & 0xFFFF));\n"
+ " #endif\n"
+ "}\n");
+ emu->addEmulatedFunction(EOpUnpackSnorm2x16, uint1,
+ "#if !defined(GL_ARB_shading_language_packing)\n"
+ " float webgl_fromSnorm(uint x)\n"
+ " {\n"
+ " int xi = (int(x) & 0x7FFF) - (int(x) & 0x8000);\n"
+ " return clamp(float(xi) / 32767.0, -1.0, 1.0);\n"
+ " }\n"
+ "#endif\n"
+ "\n"
+ "vec2 webgl_unpackSnorm2x16_emu(uint u)\n"
+ "{\n"
+ " #if defined(GL_ARB_shading_language_packing)\n"
+ " return unpackSnorm2x16(u);\n"
+ " #else\n"
+ " uint y = (u >> 16);\n"
+ " uint x = u;\n"
+ " return vec2(webgl_fromSnorm(x), webgl_fromSnorm(y));\n"
+ " #endif\n"
+ "}\n");
+ // Functions uint webgl_f32tof16(float val) and float webgl_f16tof32(uint val) are
+ // based on the OpenGL redbook Appendix Session "Floating-Point Formats Used in OpenGL".
+ emu->addEmulatedFunction(EOpPackHalf2x16, float2,
+ "#if !defined(GL_ARB_shading_language_packing)\n"
+ " uint webgl_f32tof16(float val)\n"
+ " {\n"
+ " uint f32 = floatBitsToUint(val);\n"
+ " uint f16 = 0u;\n"
+ " uint sign = (f32 >> 16) & 0x8000u;\n"
+ " int exponent = int((f32 >> 23) & 0xFFu) - 127;\n"
+ " uint mantissa = f32 & 0x007FFFFFu;\n"
+ " if (exponent == 128)\n"
+ " {\n"
+ " // Infinity or NaN\n"
+ " // NaN bits that are masked out by 0x3FF get discarded.\n"
+ " // This can turn some NaNs to infinity, but this is allowed by the spec.\n"
+ " f16 = sign | (0x1Fu << 10);\n"
+ " f16 |= (mantissa & 0x3FFu);\n"
+ " }\n"
+ " else if (exponent > 15)\n"
+ " {\n"
+ " // Overflow - flush to Infinity\n"
+ " f16 = sign | (0x1Fu << 10);\n"
+ " }\n"
+ " else if (exponent > -15)\n"
+ " {\n"
+ " // Representable value\n"
+ " exponent += 15;\n"
+ " mantissa >>= 13;\n"
+ " f16 = sign | uint(exponent << 10) | mantissa;\n"
+ " }\n"
+ " else\n"
+ " {\n"
+ " f16 = sign;\n"
+ " }\n"
+ " return f16;\n"
+ " }\n"
+ "#endif\n"
+ "\n"
+ "uint webgl_packHalf2x16_emu(vec2 v)\n"
+ "{\n"
+ " #if defined(GL_ARB_shading_language_packing)\n"
+ " return packHalf2x16(v);\n"
+ " #else\n"
+ " uint x = webgl_f32tof16(v.x);\n"
+ " uint y = webgl_f32tof16(v.y);\n"
+ " return (y << 16) | x;\n"
+ " #endif\n"
+ "}\n");
+ emu->addEmulatedFunction(EOpUnpackHalf2x16, uint1,
+ "#if !defined(GL_ARB_shading_language_packing)\n"
+ " float webgl_f16tof32(uint val)\n"
+ " {\n"
+ " uint sign = (val & 0x8000u) << 16;\n"
+ " int exponent = int((val & 0x7C00u) >> 10);\n"
+ " uint mantissa = val & 0x03FFu;\n"
+ " float f32 = 0.0;\n"
+ " if(exponent == 0)\n"
+ " {\n"
+ " if (mantissa != 0u)\n"
+ " {\n"
+ " const float scale = 1.0 / (1 << 24);\n"
+ " f32 = scale * mantissa;\n"
+ " }\n"
+ " }\n"
+ " else if (exponent == 31)\n"
+ " {\n"
+ " return uintBitsToFloat(sign | 0x7F800000u | mantissa);\n"
+ " }\n"
+ " else\n"
+ " {\n"
+ " exponent -= 15;\n"
+ " float scale;\n"
+ " if(exponent < 0)\n"
+ " {\n"
+ " scale = 1.0 / (1 << -exponent);\n"
+ " }\n"
+ " else\n"
+ " {\n"
+ " scale = 1 << exponent;\n"
+ " }\n"
+ " float decimal = 1.0 + float(mantissa) / float(1 << 10);\n"
+ " f32 = scale * decimal;\n"
+ " }\n"
+ "\n"
+ " if (sign != 0u)\n"
+ " {\n"
+ " f32 = -f32;\n"
+ " }\n"
+ "\n"
+ " return f32;\n"
+ " }\n"
+ "#endif\n"
+ "\n"
+ "vec2 webgl_unpackHalf2x16_emu(uint u)\n"
+ "{\n"
+ " #if defined(GL_ARB_shading_language_packing)\n"
+ " return unpackHalf2x16(u);\n"
+ " #else\n"
+ " uint y = (u >> 16);\n"
+ " uint x = u & 0xFFFFu;\n"
+ " return vec2(webgl_f16tof32(x), webgl_f16tof32(y));\n"
+ " #endif\n"
+ "}\n");
+ // clang-format on
+ }
+}
diff --git a/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulatorGLSL.h b/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulatorGLSL.h
index 5707a4b35a..56242598af 100644
--- a/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulatorGLSL.h
+++ b/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulatorGLSL.h
@@ -14,6 +14,12 @@ class BuiltInFunctionEmulator;
//
// This is only a workaround for OpenGL driver bugs, and isn't needed in general.
//
-void InitBuiltInFunctionEmulatorForGLSL(BuiltInFunctionEmulator *emu, sh::GLenum shaderType);
+void InitBuiltInFunctionEmulatorForGLSLWorkarounds(BuiltInFunctionEmulator *emu, sh::GLenum shaderType);
+
+//
+// This function is emulating built-in functions missing from GLSL 1.30 and higher.
+//
+void InitBuiltInFunctionEmulatorForGLSLMissingFunctions(BuiltInFunctionEmulator *emu, sh::GLenum shaderType,
+ int targetGLSLVersion);
#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
index 7123a0d5c0..50e15cbc28 100644
--- a/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulatorHLSL.cpp
+++ b/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulatorHLSL.cpp
@@ -11,10 +11,10 @@
void InitBuiltInFunctionEmulatorForHLSL(BuiltInFunctionEmulator *emu)
{
- TType float1(EbtFloat);
- TType float2(EbtFloat, 2);
- TType float3(EbtFloat, 3);
- TType float4(EbtFloat, 4);
+ TType *float1 = new TType(EbtFloat);
+ TType *float2 = new TType(EbtFloat, 2);
+ TType *float3 = new TType(EbtFloat, 3);
+ TType *float4 = new TType(EbtFloat, 4);
emu->addEmulatedFunction(EOpMod, float1, float1,
"float webgl_mod_emu(float x, float y)\n"
@@ -250,7 +250,7 @@ void InitBuiltInFunctionEmulatorForHLSL(BuiltInFunctionEmulator *emu)
" return (y << 16) | x;\n"
"}\n");
- TType uint1(EbtUInt);
+ TType *uint1 = new TType(EbtUInt);
emu->addEmulatedFunction(EOpUnpackSnorm2x16, uint1,
"float webgl_fromSnorm(in uint x) {\n"
@@ -327,9 +327,9 @@ void InitBuiltInFunctionEmulatorForHLSL(BuiltInFunctionEmulator *emu)
" return mul(float4x1(r), float1x3(c));\n"
"}\n");
- TType mat2(EbtFloat, 2, 2);
- TType mat3(EbtFloat, 3, 3);
- TType mat4(EbtFloat, 4, 4);
+ TType *mat2 = new TType(EbtFloat, 2, 2);
+ TType *mat3 = new TType(EbtFloat, 3, 3);
+ TType *mat4 = new TType(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
@@ -407,4 +407,35 @@ void InitBuiltInFunctionEmulatorForHLSL(BuiltInFunctionEmulator *emu)
" cof02, cof12, cof22, cof32, cof03, cof13, cof23, cof33 };\n"
" return cof / determinant(transpose(m));\n"
"}\n");
+
+ TType *bool1 = new TType(EbtBool);
+ TType *bool2 = new TType(EbtBool, 2);
+ TType *bool3 = new TType(EbtBool, 3);
+ TType *bool4 = new TType(EbtBool, 4);
+
+ // Emulate ESSL3 variant of mix that takes last argument as boolean vector.
+ // genType mix (genType x, genType y, genBType a): Selects which vector each returned component comes from.
+ // For a component of 'a' that is false, the corresponding component of 'x' is returned.For a component of 'a' that is true,
+ // the corresponding component of 'y' is returned.
+ emu->addEmulatedFunction(EOpMix, float1, float1, bool1,
+ "float webgl_mix_emu(float x, float y, bool a)\n"
+ "{\n"
+ " return a ? y : x;\n"
+ "}\n");
+ emu->addEmulatedFunction(EOpMix, float2, float2, bool2,
+ "float2 webgl_mix_emu(float2 x, float2 y, bool2 a)\n"
+ "{\n"
+ " return a ? y : x;\n"
+ "}\n");
+ emu->addEmulatedFunction(EOpMix, float3, float3, bool3,
+ "float3 webgl_mix_emu(float3 x, float3 y, bool3 a)\n"
+ "{\n"
+ " return a ? y : x;\n"
+ "}\n");
+ emu->addEmulatedFunction(EOpMix, float4, float4, bool4,
+ "float4 webgl_mix_emu(float4 x, float4 y, bool4 a)\n"
+ "{\n"
+ " return a ? y : x;\n"
+ "}\n");
+
}
diff --git a/src/3rdparty/angle/src/compiler/translator/Cache.cpp b/src/3rdparty/angle/src/compiler/translator/Cache.cpp
new file mode 100644
index 0000000000..57a43700ca
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/translator/Cache.cpp
@@ -0,0 +1,100 @@
+//
+// Copyright (c) 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.
+//
+
+// Cache.cpp: Implements a cache for various commonly created objects.
+
+#include <limits>
+
+#include "common/angleutils.h"
+#include "common/debug.h"
+#include "compiler/translator/Cache.h"
+
+namespace
+{
+
+class TScopedAllocator : angle::NonCopyable
+{
+ public:
+ TScopedAllocator(TPoolAllocator *allocator)
+ : mPreviousAllocator(GetGlobalPoolAllocator())
+ {
+ SetGlobalPoolAllocator(allocator);
+ }
+ ~TScopedAllocator()
+ {
+ SetGlobalPoolAllocator(mPreviousAllocator);
+ }
+
+ private:
+ TPoolAllocator *mPreviousAllocator;
+};
+
+} // namespace
+
+TCache::TypeKey::TypeKey(TBasicType basicType,
+ TPrecision precision,
+ TQualifier qualifier,
+ unsigned char primarySize,
+ unsigned char secondarySize)
+{
+ static_assert(sizeof(components) <= sizeof(value),
+ "TypeKey::value is too small");
+
+ const size_t MaxEnumValue = std::numeric_limits<EnumComponentType>::max();
+ UNUSED_ASSERTION_VARIABLE(MaxEnumValue);
+
+ // TODO: change to static_assert() once we deprecate MSVC 2013 support
+ ASSERT(MaxEnumValue >= EbtLast &&
+ MaxEnumValue >= EbpLast &&
+ MaxEnumValue >= EvqLast &&
+ "TypeKey::EnumComponentType is too small");
+
+ value = 0;
+ components.basicType = static_cast<EnumComponentType>(basicType);
+ components.precision = static_cast<EnumComponentType>(precision);
+ components.qualifier = static_cast<EnumComponentType>(qualifier);
+ components.primarySize = primarySize;
+ components.secondarySize = secondarySize;
+}
+
+TCache *TCache::sCache = nullptr;
+
+void TCache::initialize()
+{
+ if (sCache == nullptr)
+ {
+ sCache = new TCache();
+ }
+}
+
+void TCache::destroy()
+{
+ SafeDelete(sCache);
+}
+
+const TType *TCache::getType(TBasicType basicType,
+ TPrecision precision,
+ TQualifier qualifier,
+ unsigned char primarySize,
+ unsigned char secondarySize)
+{
+ TypeKey key(basicType, precision, qualifier,
+ primarySize, secondarySize);
+ auto it = sCache->mTypes.find(key);
+ if (it != sCache->mTypes.end())
+ {
+ return it->second;
+ }
+
+ TScopedAllocator scopedAllocator(&sCache->mAllocator);
+
+ TType *type = new TType(basicType, precision, qualifier,
+ primarySize, secondarySize);
+ type->realize();
+ sCache->mTypes.insert(std::make_pair(key, type));
+
+ return type;
+}
diff --git a/src/3rdparty/angle/src/compiler/translator/Cache.h b/src/3rdparty/angle/src/compiler/translator/Cache.h
new file mode 100644
index 0000000000..1d2abb77e1
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/translator/Cache.h
@@ -0,0 +1,90 @@
+//
+// Copyright (c) 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.
+//
+
+// Cache.h: Implements a cache for various commonly created objects.
+
+#ifndef COMPILER_TRANSLATOR_CACHE_H_
+#define COMPILER_TRANSLATOR_CACHE_H_
+
+#include <stdint.h>
+#include <string.h>
+#include <map>
+
+#include "compiler/translator/Types.h"
+#include "compiler/translator/PoolAlloc.h"
+
+class TCache
+{
+ public:
+
+ static void initialize();
+ static void destroy();
+
+ static const TType *getType(TBasicType basicType,
+ TPrecision precision)
+ {
+ return getType(basicType, precision, EvqTemporary,
+ 1, 1);
+ }
+ static const TType *getType(TBasicType basicType,
+ unsigned char primarySize = 1,
+ unsigned char secondarySize = 1)
+ {
+ return getType(basicType, EbpUndefined, EvqGlobal,
+ primarySize, secondarySize);
+ }
+ static const TType *getType(TBasicType basicType,
+ TQualifier qualifier,
+ unsigned char primarySize = 1,
+ unsigned char secondarySize = 1)
+ {
+ return getType(basicType, EbpUndefined, qualifier,
+ primarySize, secondarySize);
+ }
+ static const TType *getType(TBasicType basicType,
+ TPrecision precision,
+ TQualifier qualifier,
+ unsigned char primarySize,
+ unsigned char secondarySize);
+
+ private:
+ TCache()
+ {
+ }
+
+ union TypeKey
+ {
+ TypeKey(TBasicType basicType,
+ TPrecision precision,
+ TQualifier qualifier,
+ unsigned char primarySize,
+ unsigned char secondarySize);
+
+ typedef uint8_t EnumComponentType;
+ struct
+ {
+ EnumComponentType basicType;
+ EnumComponentType precision;
+ EnumComponentType qualifier;
+ unsigned char primarySize;
+ unsigned char secondarySize;
+ } components;
+ uint64_t value;
+
+ bool operator < (const TypeKey &other) const
+ {
+ return value < other.value;
+ }
+ };
+ typedef std::map<TypeKey, const TType*> TypeMap;
+
+ TypeMap mTypes;
+ TPoolAllocator mAllocator;
+
+ static TCache *sCache;
+};
+
+#endif // COMPILER_TRANSLATOR_CACHE_H_
diff --git a/src/3rdparty/angle/src/compiler/translator/CallDAG.cpp b/src/3rdparty/angle/src/compiler/translator/CallDAG.cpp
new file mode 100644
index 0000000000..10f0eb937c
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/translator/CallDAG.cpp
@@ -0,0 +1,293 @@
+//
+// 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.
+//
+
+// CallDAG.h: Implements a call graph DAG of functions to be re-used accross
+// analyses, allows to efficiently traverse the functions in topological
+// order.
+
+#include "compiler/translator/CallDAG.h"
+#include "compiler/translator/InfoSink.h"
+
+// The CallDAGCreator does all the processing required to create the CallDAG
+// structure so that the latter contains only the necessary variables.
+class CallDAG::CallDAGCreator : public TIntermTraverser
+{
+ public:
+ CallDAGCreator(TInfoSinkBase *info)
+ : TIntermTraverser(true, false, true),
+ mCreationInfo(info),
+ mCurrentFunction(nullptr),
+ mCurrentIndex(0)
+ {
+ }
+
+ InitResult assignIndices()
+ {
+ int skipped = 0;
+ for (auto &it : mFunctions)
+ {
+ // Skip unimplemented functions
+ if (it.second.node)
+ {
+ InitResult result = assignIndicesInternal(&it.second);
+ if (result != INITDAG_SUCCESS)
+ {
+ *mCreationInfo << "\n";
+ return result;
+ }
+ }
+ else
+ {
+ skipped++;
+ }
+ }
+ ASSERT(mFunctions.size() == mCurrentIndex + skipped);
+ return INITDAG_SUCCESS;
+ }
+
+ void fillDataStructures(std::vector<Record> *records, std::map<int, int> *idToIndex)
+ {
+ ASSERT(records->empty());
+ ASSERT(idToIndex->empty());
+
+ records->resize(mCurrentIndex);
+
+ for (auto &it : mFunctions)
+ {
+ CreatorFunctionData &data = it.second;
+ // Skip unimplemented functions
+ if (!data.node)
+ {
+ continue;
+ }
+ ASSERT(data.index < records->size());
+ Record &record = (*records)[data.index];
+
+ record.name = data.name.data();
+ record.node = data.node;
+
+ record.callees.reserve(data.callees.size());
+ for (auto &callee : data.callees)
+ {
+ record.callees.push_back(static_cast<int>(callee->index));
+ }
+
+ (*idToIndex)[data.node->getFunctionId()] = static_cast<int>(data.index);
+ }
+ }
+
+ private:
+
+ struct CreatorFunctionData
+ {
+ CreatorFunctionData()
+ : node(nullptr),
+ index(0),
+ indexAssigned(false),
+ visiting(false)
+ {
+ }
+
+ std::set<CreatorFunctionData*> callees;
+ TIntermAggregate *node;
+ TString name;
+ size_t index;
+ bool indexAssigned;
+ bool visiting;
+ };
+
+ // Aggregates the AST node for each function as well as the name of the functions called by it
+ bool visitAggregate(Visit visit, TIntermAggregate *node) override
+ {
+ switch (node->getOp())
+ {
+ case EOpPrototype:
+ if (visit == PreVisit)
+ {
+ // Function declaration, create an empty record.
+ auto& record = mFunctions[node->getName()];
+ record.name = node->getName();
+ }
+ break;
+ case EOpFunction:
+ {
+ // Function definition, create the record if need be and remember the node.
+ if (visit == PreVisit)
+ {
+ auto it = mFunctions.find(node->getName());
+
+ if (it == mFunctions.end())
+ {
+ mCurrentFunction = &mFunctions[node->getName()];
+ }
+ else
+ {
+ mCurrentFunction = &it->second;
+ }
+
+ mCurrentFunction->node = node;
+ mCurrentFunction->name = node->getName();
+
+ }
+ else if (visit == PostVisit)
+ {
+ mCurrentFunction = nullptr;
+ }
+ break;
+ }
+ case EOpFunctionCall:
+ {
+ // Function call, add the callees
+ if (visit == PreVisit)
+ {
+ // Do not handle calls to builtin functions
+ if (node->isUserDefined())
+ {
+ auto it = mFunctions.find(node->getName());
+ ASSERT(it != mFunctions.end());
+
+ // We might be in a top-level function call to set a global variable
+ if (mCurrentFunction)
+ {
+ mCurrentFunction->callees.insert(&it->second);
+ }
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ return true;
+ }
+
+ // Recursively assigns indices to a sub DAG
+ InitResult assignIndicesInternal(CreatorFunctionData *function)
+ {
+ ASSERT(function);
+
+ if (!function->node)
+ {
+ *mCreationInfo << "Undefined function '" << function->name
+ << ")' used in the following call chain:";
+ return INITDAG_UNDEFINED;
+ }
+
+ if (function->indexAssigned)
+ {
+ return INITDAG_SUCCESS;
+ }
+
+ if (function->visiting)
+ {
+ if (mCreationInfo)
+ {
+ *mCreationInfo << "Recursive function call in the following call chain:" << function->name;
+ }
+ return INITDAG_RECURSION;
+ }
+ function->visiting = true;
+
+ for (auto &callee : function->callees)
+ {
+ InitResult result = assignIndicesInternal(callee);
+ if (result != INITDAG_SUCCESS)
+ {
+ // We know that there is an issue with the call chain in the AST,
+ // print the link of the chain we were processing.
+ if (mCreationInfo)
+ {
+ *mCreationInfo << " <- " << function->name << ")";
+ }
+ return result;
+ }
+ }
+
+ function->index = mCurrentIndex++;
+ function->indexAssigned = true;
+
+ function->visiting = false;
+ return INITDAG_SUCCESS;
+ }
+
+ TInfoSinkBase *mCreationInfo;
+
+ std::map<TString, CreatorFunctionData> mFunctions;
+ CreatorFunctionData *mCurrentFunction;
+ size_t mCurrentIndex;
+};
+
+// CallDAG
+
+CallDAG::CallDAG()
+{
+}
+
+CallDAG::~CallDAG()
+{
+}
+
+const size_t CallDAG::InvalidIndex = std::numeric_limits<size_t>::max();
+
+size_t CallDAG::findIndex(const TIntermAggregate *function) const
+{
+ TOperator op = function->getOp();
+ ASSERT(op == EOpPrototype || op == EOpFunction || op == EOpFunctionCall);
+ UNUSED_ASSERTION_VARIABLE(op);
+
+ auto it = mFunctionIdToIndex.find(function->getFunctionId());
+
+ if (it == mFunctionIdToIndex.end())
+ {
+ return InvalidIndex;
+ }
+ else
+ {
+ return it->second;
+ }
+}
+
+const CallDAG::Record &CallDAG::getRecordFromIndex(size_t index) const
+{
+ ASSERT(index != InvalidIndex && index < mRecords.size());
+ return mRecords[index];
+}
+
+const CallDAG::Record &CallDAG::getRecord(const TIntermAggregate *function) const
+{
+ size_t index = findIndex(function);
+ ASSERT(index != InvalidIndex && index < mRecords.size());
+ return mRecords[index];
+}
+
+size_t CallDAG::size() const
+{
+ return mRecords.size();
+}
+
+void CallDAG::clear()
+{
+ mRecords.clear();
+ mFunctionIdToIndex.clear();
+}
+
+CallDAG::InitResult CallDAG::init(TIntermNode *root, TInfoSinkBase *info)
+{
+ CallDAGCreator creator(info);
+
+ // Creates the mapping of functions to callees
+ root->traverse(&creator);
+
+ // Does the topological sort and detects recursions
+ InitResult result = creator.assignIndices();
+ if (result != INITDAG_SUCCESS)
+ {
+ return result;
+ }
+
+ creator.fillDataStructures(&mRecords, &mFunctionIdToIndex);
+ return INITDAG_SUCCESS;
+}
diff --git a/src/3rdparty/angle/src/compiler/translator/CallDAG.h b/src/3rdparty/angle/src/compiler/translator/CallDAG.h
new file mode 100644
index 0000000000..06c377db00
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/translator/CallDAG.h
@@ -0,0 +1,75 @@
+//
+// 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.
+//
+
+// CallDAG.h: Defines a call graph DAG of functions to be re-used accross
+// analyses, allows to efficiently traverse the functions in topological
+// order.
+
+#ifndef COMPILER_TRANSLATOR_CALLDAG_H_
+#define COMPILER_TRANSLATOR_CALLDAG_H_
+
+#include <map>
+
+#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/VariableInfo.h"
+
+
+// The translator needs to analyze the the graph of the function calls
+// to run checks and analyses; since in GLSL recursion is not allowed
+// that graph is a DAG.
+// This class is used to precompute that function call DAG so that it
+// can be reused by multiple analyses.
+//
+// It stores a vector of function records, with one record per function.
+// Records are accessed by index but a mangled function name can be converted
+// to the index of the corresponding record. The records mostly contain the
+// AST node of the function and the indices of the function's callees.
+//
+// In addition, records are in reverse topological order: a function F being
+// called by a function G will have index index(F) < index(G), that way
+// depth-first analysis becomes analysis in the order of indices.
+
+class CallDAG : angle::NonCopyable
+{
+ public:
+ CallDAG();
+ ~CallDAG();
+
+ struct Record
+ {
+ std::string name;
+ TIntermAggregate *node;
+ std::vector<int> callees;
+ };
+
+ enum InitResult
+ {
+ INITDAG_SUCCESS,
+ INITDAG_RECURSION,
+ INITDAG_UNDEFINED,
+ };
+
+ // Returns INITDAG_SUCCESS if it was able to create the DAG, otherwise prints
+ // the initialization error in info, if present.
+ InitResult init(TIntermNode *root, TInfoSinkBase *info);
+
+ // Returns InvalidIndex if the function wasn't found
+ size_t findIndex(const TIntermAggregate *function) const;
+
+ const Record &getRecordFromIndex(size_t index) const;
+ const Record &getRecord(const TIntermAggregate *function) const;
+ size_t size() const;
+ void clear();
+
+ const static size_t InvalidIndex;
+ private:
+ std::vector<Record> mRecords;
+ std::map<int, int> mFunctionIdToIndex;
+
+ class CallDAGCreator;
+};
+
+#endif // COMPILER_TRANSLATOR_CALLDAG_H_
diff --git a/src/3rdparty/angle/src/compiler/translator/CodeGen.cpp b/src/3rdparty/angle/src/compiler/translator/CodeGen.cpp
index 5e3eb1cc05..f099bccf15 100644
--- a/src/3rdparty/angle/src/compiler/translator/CodeGen.cpp
+++ b/src/3rdparty/angle/src/compiler/translator/CodeGen.cpp
@@ -4,8 +4,14 @@
// found in the LICENSE file.
//
+#ifdef ANGLE_ENABLE_ESSL
#include "compiler/translator/TranslatorESSL.h"
+#endif
+
+#ifdef ANGLE_ENABLE_GLSL
#include "compiler/translator/TranslatorGLSL.h"
+#endif
+
#ifdef ANGLE_ENABLE_HLSL
#include "compiler/translator/TranslatorHLSL.h"
#endif // ANGLE_ENABLE_HLSL
@@ -20,22 +26,44 @@ TCompiler* ConstructCompiler(
{
switch (output) {
case SH_ESSL_OUTPUT:
+#ifdef ANGLE_ENABLE_ESSL
return new TranslatorESSL(type, spec);
- case SH_GLSL_CORE_OUTPUT:
+#else
+ // This compiler is not supported in this
+ // configuration. Return NULL per the ShConstructCompiler API.
+ return nullptr;
+#endif // ANGLE_ENABLE_ESSL
+ case SH_GLSL_130_OUTPUT:
+ case SH_GLSL_140_OUTPUT:
+ case SH_GLSL_150_CORE_OUTPUT:
+ case SH_GLSL_330_CORE_OUTPUT:
+ case SH_GLSL_400_CORE_OUTPUT:
+ case SH_GLSL_410_CORE_OUTPUT:
+ case SH_GLSL_420_CORE_OUTPUT:
+ case SH_GLSL_430_CORE_OUTPUT:
+ case SH_GLSL_440_CORE_OUTPUT:
+ case SH_GLSL_450_CORE_OUTPUT:
case SH_GLSL_COMPATIBILITY_OUTPUT:
+#ifdef ANGLE_ENABLE_GLSL
return new TranslatorGLSL(type, spec, output);
- case SH_HLSL9_OUTPUT:
- case SH_HLSL11_OUTPUT:
+#else
+ // This compiler is not supported in this
+ // configuration. Return NULL per the ShConstructCompiler API.
+ return nullptr;
+#endif // ANGLE_ENABLE_GLSL
+ case SH_HLSL_3_0_OUTPUT:
+ case SH_HLSL_4_1_OUTPUT:
+ case SH_HLSL_4_0_FL9_3_OUTPUT:
#ifdef ANGLE_ENABLE_HLSL
return new TranslatorHLSL(type, spec, output);
#else
// This compiler is not supported in this
// configuration. Return NULL per the ShConstructCompiler API.
- return NULL;
+ return nullptr;
#endif // ANGLE_ENABLE_HLSL
default:
// Unknown format. Return NULL per the ShConstructCompiler API.
- return NULL;
+ return nullptr;
}
}
diff --git a/src/3rdparty/angle/src/compiler/translator/Common.h b/src/3rdparty/angle/src/compiler/translator/Common.h
index ac1aef0f4c..60223232af 100644
--- a/src/3rdparty/angle/src/compiler/translator/Common.h
+++ b/src/3rdparty/angle/src/compiler/translator/Common.h
@@ -14,9 +14,9 @@
#include <limits>
#include <stdio.h>
-#include "compiler/translator/PoolAlloc.h"
-#include "compiler/translator/compilerdebug.h"
#include "common/angleutils.h"
+#include "common/debug.h"
+#include "compiler/translator/PoolAlloc.h"
struct TSourceLoc {
int first_file;
@@ -60,18 +60,21 @@ inline TString* NewPoolTString(const char* s)
//
// Pool allocator versions of vectors, lists, and maps
//
-template <class T> class TVector : public std::vector<T, pool_allocator<T> > {
-public:
- typedef typename std::vector<T, pool_allocator<T> >::size_type size_type;
- TVector() : std::vector<T, pool_allocator<T> >() {}
- TVector(const pool_allocator<T>& a) : std::vector<T, pool_allocator<T> >(a) {}
- TVector(size_type i): std::vector<T, pool_allocator<T> >(i) {}
+template <class T>
+class TVector : public std::vector<T, pool_allocator<T>>
+{
+ public:
+ typedef typename std::vector<T, pool_allocator<T>>::size_type size_type;
+ TVector() : std::vector<T, pool_allocator<T>>() {}
+ TVector(const pool_allocator<T> &a) : std::vector<T, pool_allocator<T>>(a) {}
+ TVector(size_type i) : std::vector<T, pool_allocator<T>>(i) {}
};
-template <class K, class D, class CMP = std::less<K> >
-class TMap : public std::map<K, D, CMP, pool_allocator<std::pair<const K, D> > > {
-public:
- typedef pool_allocator<std::pair<const K, D> > tAllocator;
+template <class K, class D, class CMP = std::less<K>>
+class TMap : public std::map<K, D, CMP, pool_allocator<std::pair<const K, D>>>
+{
+ public:
+ typedef pool_allocator<std::pair<const K, D>> tAllocator;
TMap() : std::map<K, D, CMP, tAllocator>() {}
// use correct two-stage name lookup supported in gcc 3.4 and above
diff --git a/src/3rdparty/angle/src/compiler/translator/Compiler.cpp b/src/3rdparty/angle/src/compiler/translator/Compiler.cpp
index 534861ca70..18524ce569 100644
--- a/src/3rdparty/angle/src/compiler/translator/Compiler.cpp
+++ b/src/3rdparty/angle/src/compiler/translator/Compiler.cpp
@@ -4,15 +4,19 @@
// found in the LICENSE file.
//
+#include "compiler/translator/Cache.h"
#include "compiler/translator/Compiler.h"
-#include "compiler/translator/DetectCallDepth.h"
+#include "compiler/translator/CallDAG.h"
#include "compiler/translator/ForLoopUnroll.h"
#include "compiler/translator/Initialize.h"
#include "compiler/translator/InitializeParseContext.h"
#include "compiler/translator/InitializeVariables.h"
#include "compiler/translator/ParseContext.h"
+#include "compiler/translator/PruneEmptyDeclarations.h"
#include "compiler/translator/RegenerateStructNames.h"
+#include "compiler/translator/RemovePow.h"
#include "compiler/translator/RenameFunction.h"
+#include "compiler/translator/RewriteDoWhile.h"
#include "compiler/translator/ScalarizeVecAndMatConstructorArgs.h"
#include "compiler/translator/UnfoldShortCircuitAST.h"
#include "compiler/translator/ValidateLimitations.h"
@@ -33,6 +37,20 @@ bool IsWebGLBasedSpec(ShShaderSpec spec)
spec == SH_WEBGL2_SPEC);
}
+bool IsGLSL130OrNewer(ShShaderOutput output)
+{
+ return (output == SH_GLSL_130_OUTPUT ||
+ output == SH_GLSL_140_OUTPUT ||
+ output == SH_GLSL_150_CORE_OUTPUT ||
+ output == SH_GLSL_330_CORE_OUTPUT ||
+ output == SH_GLSL_400_CORE_OUTPUT ||
+ output == SH_GLSL_410_CORE_OUTPUT ||
+ output == SH_GLSL_420_CORE_OUTPUT ||
+ output == SH_GLSL_430_CORE_OUTPUT ||
+ output == SH_GLSL_440_CORE_OUTPUT ||
+ output == SH_GLSL_450_CORE_OUTPUT);
+}
+
size_t GetGlobalMaxTokenSize(ShShaderSpec spec)
{
// WebGL defines a max token legnth of 256, while ES2 leaves max token
@@ -126,7 +144,8 @@ TCompiler::TCompiler(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output)
fragmentPrecisionHigh(false),
clampingStrategy(SH_CLAMP_WITH_CLAMP_INTRINSIC),
builtInFunctionEmulator(),
- mSourcePath(NULL)
+ mSourcePath(NULL),
+ mTemporaryIndex(0)
{
}
@@ -134,6 +153,15 @@ TCompiler::~TCompiler()
{
}
+bool TCompiler::shouldRunLoopAndIndexingValidation(int compileOptions) const
+{
+ // If compiling an ESSL 1.00 shader for WebGL, or if its been requested through the API,
+ // validate loop and indexing as well (to verify that the shader only uses minimal functionality
+ // of ESSL 1.00 as in Appendix A of the spec).
+ return (IsWebGLBasedSpec(shaderSpec) && shaderVersion == 100) ||
+ (compileOptions & SH_VALIDATE_LOOP_INDEXING);
+}
+
bool TCompiler::Init(const ShBuiltInResources& resources)
{
shaderVersion = 100;
@@ -165,8 +193,9 @@ TIntermNode *TCompiler::compileTreeForTesting(const char* const shaderStrings[],
return compileTreeImpl(shaderStrings, numStrings, compileOptions);
}
-TIntermNode *TCompiler::compileTreeImpl(const char* const shaderStrings[],
- size_t numStrings, int compileOptions)
+TIntermNode *TCompiler::compileTreeImpl(const char *const shaderStrings[],
+ size_t numStrings,
+ const int compileOptions)
{
clearResults();
@@ -176,10 +205,6 @@ TIntermNode *TCompiler::compileTreeImpl(const char* const shaderStrings[],
// 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.
size_t firstSource = 0;
if (compileOptions & SH_SOURCE_PATH)
@@ -188,13 +213,11 @@ TIntermNode *TCompiler::compileTreeImpl(const char* const shaderStrings[],
++firstSource;
}
- bool debugShaderPrecision = getResources().WEBGL_debug_shader_precision == 1;
TIntermediate intermediate(infoSink);
- TParseContext parseContext(symbolTable, extensionBehavior, intermediate,
- shaderType, shaderSpec, compileOptions, true,
- infoSink, debugShaderPrecision);
+ TParseContext parseContext(symbolTable, extensionBehavior, intermediate, shaderType, shaderSpec,
+ compileOptions, true, infoSink, getResources());
- parseContext.fragmentPrecisionHigh = fragmentPrecisionHigh;
+ parseContext.setFragmentPrecisionHighOnESSL1(fragmentPrecisionHigh);
SetGlobalParseContext(&parseContext);
// We preserve symbols at the built-in level from compile-to-compile.
@@ -203,8 +226,8 @@ TIntermNode *TCompiler::compileTreeImpl(const char* const shaderStrings[],
// Parse shader.
bool success =
- (PaParseStrings(numStrings - firstSource, &shaderStrings[firstSource], NULL, &parseContext) == 0) &&
- (parseContext.treeRoot != NULL);
+ (PaParseStrings(numStrings - firstSource, &shaderStrings[firstSource], nullptr, &parseContext) == 0) &&
+ (parseContext.getTreeRoot() != nullptr);
shaderVersion = parseContext.getShaderVersion();
if (success && MapSpecToShaderVersion(shaderSpec) < shaderVersion)
@@ -214,7 +237,7 @@ TIntermNode *TCompiler::compileTreeImpl(const char* const shaderStrings[],
success = false;
}
- TIntermNode *root = NULL;
+ TIntermNode *root = nullptr;
if (success)
{
@@ -224,20 +247,42 @@ TIntermNode *TCompiler::compileTreeImpl(const char* const shaderStrings[],
symbolTable.setGlobalInvariant();
}
- root = parseContext.treeRoot;
- success = intermediate.postProcess(root);
+ root = parseContext.getTreeRoot();
+ root = intermediate.postProcess(root);
+
+ // Highp might have been auto-enabled based on shader version
+ fragmentPrecisionHigh = parseContext.getFragmentPrecisionHigh();
// Disallow expressions deemed too complex.
if (success && (compileOptions & SH_LIMIT_EXPRESSION_COMPLEXITY))
success = limitExpressionComplexity(root);
+ // Create the function DAG and check there is no recursion
+ if (success)
+ success = initCallDag(root);
+
+ if (success && (compileOptions & SH_LIMIT_CALL_STACK_DEPTH))
+ success = checkCallDepth();
+
+ // Checks which functions are used and if "main" exists
if (success)
- success = detectCallDepth(root, infoSink, (compileOptions & SH_LIMIT_CALL_STACK_DEPTH) != 0);
+ {
+ functionMetadata.clear();
+ functionMetadata.resize(mCallDag.size());
+ success = tagUsedFunctions();
+ }
+
+ if (success && !(compileOptions & SH_DONT_PRUNE_UNUSED_FUNCTIONS))
+ success = pruneUnusedFunctions(root);
+
+ // Prune empty declarations to work around driver bugs and to keep declaration output simple.
+ if (success)
+ PruneEmptyDeclarations(root);
if (success && shaderVersion == 300 && shaderType == GL_FRAGMENT_SHADER)
success = validateOutputs(root);
- if (success && (compileOptions & SH_VALIDATE_LOOP_INDEXING))
+ if (success && shouldRunLoopAndIndexingValidation(compileOptions))
success = validateLimitations(root);
if (success && (compileOptions & SH_TIMING_RESTRICTIONS))
@@ -249,12 +294,14 @@ TIntermNode *TCompiler::compileTreeImpl(const char* const shaderStrings[],
// Unroll for-loop markup needs to happen after validateLimitations pass.
if (success && (compileOptions & SH_UNROLL_FOR_LOOP_WITH_INTEGER_INDEX))
{
- ForLoopUnrollMarker marker(ForLoopUnrollMarker::kIntegerIndex);
+ ForLoopUnrollMarker marker(ForLoopUnrollMarker::kIntegerIndex,
+ shouldRunLoopAndIndexingValidation(compileOptions));
root->traverse(&marker);
}
if (success && (compileOptions & SH_UNROLL_FOR_LOOP_WITH_SAMPLER_ARRAY_INDEX))
{
- ForLoopUnrollMarker marker(ForLoopUnrollMarker::kSamplerArrayIndex);
+ ForLoopUnrollMarker marker(ForLoopUnrollMarker::kSamplerArrayIndex,
+ shouldRunLoopAndIndexingValidation(compileOptions));
root->traverse(&marker);
if (marker.samplerArrayIndexIsFloatLoopIndex())
{
@@ -275,9 +322,16 @@ TIntermNode *TCompiler::compileTreeImpl(const char* const shaderStrings[],
if (success && (compileOptions & SH_CLAMP_INDIRECT_ARRAY_BOUNDS))
arrayBoundsClamper.MarkIndirectArrayBoundsForClamping(root);
- if (success && shaderType == GL_VERTEX_SHADER && (compileOptions & SH_INIT_GL_POSITION))
+ // gl_Position is always written in compatibility output mode
+ if (success && shaderType == GL_VERTEX_SHADER &&
+ ((compileOptions & SH_INIT_GL_POSITION) ||
+ (outputType == SH_GLSL_COMPATIBILITY_OUTPUT)))
initializeGLPosition(root);
+ // This pass might emit short circuits so keep it before the short circuit unfolding
+ if (success && (compileOptions & SH_REWRITE_DO_WHILE_LOOPS))
+ RewriteDoWhile(root, getTemporaryIndex());
+
if (success && (compileOptions & SH_UNFOLD_SHORT_CIRCUIT))
{
UnfoldShortCircuitAST unfoldShortCircuit;
@@ -285,7 +339,12 @@ TIntermNode *TCompiler::compileTreeImpl(const char* const shaderStrings[],
unfoldShortCircuit.updateTree();
}
- if (success && (compileOptions & SH_VARIABLES))
+ if (success && (compileOptions & SH_REMOVE_POW_WITH_CONSTANT_EXPONENT))
+ {
+ RemovePow(root);
+ }
+
+ if (success && shouldCollectVariables(compileOptions))
{
collectVariables(root);
if (compileOptions & SH_ENFORCE_PACKING_RESTRICTIONS)
@@ -369,11 +428,6 @@ bool TCompiler::InitBuiltInSymbolTable(const ShBuiltInResources &resources)
floatingPoint.secondarySize = 1;
floatingPoint.array = false;
- TPublicType sampler;
- sampler.primarySize = 1;
- sampler.secondarySize = 1;
- sampler.array = false;
-
switch(shaderType)
{
case GL_FRAGMENT_SHADER:
@@ -386,14 +440,15 @@ bool TCompiler::InitBuiltInSymbolTable(const ShBuiltInResources &resources)
default:
assert(false && "Language not supported");
}
- // We set defaults for all the sampler types, even those that are
+ // Set defaults for sampler types that have default precision, even those that are
// only available if an extension exists.
- for (int samplerType = EbtGuardSamplerBegin + 1;
- samplerType < EbtGuardSamplerEnd; ++samplerType)
- {
- sampler.type = static_cast<TBasicType>(samplerType);
- symbolTable.setDefaultPrecision(sampler, EbpLow);
- }
+ // New sampler types in ESSL3 don't have default precision. ESSL1 types do.
+ initSamplerDefaultPrecision(EbtSampler2D);
+ initSamplerDefaultPrecision(EbtSamplerCube);
+ // SamplerExternalOES is specified in the extension to have default precision.
+ initSamplerDefaultPrecision(EbtSamplerExternalOES);
+ // It isn't specified whether Sampler2DRect has default precision.
+ initSamplerDefaultPrecision(EbtSampler2DRect);
InsertBuiltInFunctions(shaderType, shaderSpec, resources, symbolTable);
@@ -402,6 +457,17 @@ bool TCompiler::InitBuiltInSymbolTable(const ShBuiltInResources &resources)
return true;
}
+void TCompiler::initSamplerDefaultPrecision(TBasicType samplerType)
+{
+ ASSERT(samplerType > EbtGuardSamplerBegin && samplerType < EbtGuardSamplerEnd);
+ TPublicType sampler;
+ sampler.primarySize = 1;
+ sampler.secondarySize = 1;
+ sampler.array = false;
+ sampler.type = samplerType;
+ symbolTable.setDefaultPrecision(sampler, EbpLow);
+}
+
void TCompiler::setResourceString()
{
std::ostringstream strstream;
@@ -420,6 +486,7 @@ void TCompiler::setResourceString()
<< ":FragmentPrecisionHigh:" << compileResources.FragmentPrecisionHigh
<< ":MaxExpressionComplexity:" << compileResources.MaxExpressionComplexity
<< ":MaxCallStackDepth:" << compileResources.MaxCallStackDepth
+ << ":EXT_blend_func_extended:" << compileResources.EXT_blend_func_extended
<< ":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
@@ -429,6 +496,7 @@ void TCompiler::setResourceString()
<< ":MaxFragmentInputVectors:" << compileResources.MaxFragmentInputVectors
<< ":MinProgramTexelOffset:" << compileResources.MinProgramTexelOffset
<< ":MaxProgramTexelOffset:" << compileResources.MaxProgramTexelOffset
+ << ":MaxDualSourceDrawBuffers:" << compileResources.MaxDualSourceDrawBuffers
<< ":NV_draw_buffers:" << compileResources.NV_draw_buffers
<< ":WEBGL_debug_shader_precision:" << compileResources.WEBGL_debug_shader_precision;
@@ -454,39 +522,175 @@ void TCompiler::clearResults()
nameMap.clear();
mSourcePath = NULL;
+ mTemporaryIndex = 0;
}
-bool TCompiler::detectCallDepth(TIntermNode* inputRoot, TInfoSink& inputInfoSink, bool limitCallStackDepth)
+bool TCompiler::initCallDag(TIntermNode *root)
{
- DetectCallDepth detect(inputInfoSink, limitCallStackDepth, maxCallStackDepth);
- inputRoot->traverse(&detect);
- switch (detect.detectCallDepth())
+ mCallDag.clear();
+
+ switch (mCallDag.init(root, &infoSink.info))
{
- case DetectCallDepth::kErrorNone:
+ case CallDAG::INITDAG_SUCCESS:
return true;
- case DetectCallDepth::kErrorMissingMain:
- inputInfoSink.info.prefix(EPrefixError);
- inputInfoSink.info << "Missing main()";
- return false;
- case DetectCallDepth::kErrorRecursion:
- inputInfoSink.info.prefix(EPrefixError);
- inputInfoSink.info << "Function recursion detected";
- return false;
- case DetectCallDepth::kErrorMaxDepthExceeded:
- inputInfoSink.info.prefix(EPrefixError);
- inputInfoSink.info << "Function call stack too deep";
+ case CallDAG::INITDAG_RECURSION:
+ infoSink.info.prefix(EPrefixError);
+ infoSink.info << "Function recursion detected";
return false;
- default:
- UNREACHABLE();
+ case CallDAG::INITDAG_UNDEFINED:
+ infoSink.info.prefix(EPrefixError);
+ infoSink.info << "Unimplemented function detected";
return false;
}
+
+ UNREACHABLE();
+ return true;
+}
+
+bool TCompiler::checkCallDepth()
+{
+ std::vector<int> depths(mCallDag.size());
+
+ for (size_t i = 0; i < mCallDag.size(); i++)
+ {
+ int depth = 0;
+ auto &record = mCallDag.getRecordFromIndex(i);
+
+ for (auto &calleeIndex : record.callees)
+ {
+ depth = std::max(depth, depths[calleeIndex] + 1);
+ }
+
+ depths[i] = depth;
+
+ if (depth >= maxCallStackDepth)
+ {
+ // Trace back the function chain to have a meaningful info log.
+ infoSink.info.prefix(EPrefixError);
+ infoSink.info << "Call stack too deep (larger than " << maxCallStackDepth
+ << ") with the following call chain: " << record.name;
+
+ int currentFunction = static_cast<int>(i);
+ int currentDepth = depth;
+
+ while (currentFunction != -1)
+ {
+ infoSink.info << " -> " << mCallDag.getRecordFromIndex(currentFunction).name;
+
+ int nextFunction = -1;
+ for (auto& calleeIndex : mCallDag.getRecordFromIndex(currentFunction).callees)
+ {
+ if (depths[calleeIndex] == currentDepth - 1)
+ {
+ currentDepth--;
+ nextFunction = calleeIndex;
+ }
+ }
+
+ currentFunction = nextFunction;
+ }
+
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool TCompiler::tagUsedFunctions()
+{
+ // Search from main, starting from the end of the DAG as it usually is the root.
+ for (size_t i = mCallDag.size(); i-- > 0;)
+ {
+ if (mCallDag.getRecordFromIndex(i).name == "main(")
+ {
+ internalTagUsedFunction(i);
+ return true;
+ }
+ }
+
+ infoSink.info.prefix(EPrefixError);
+ infoSink.info << "Missing main()\n";
+ return false;
+}
+
+void TCompiler::internalTagUsedFunction(size_t index)
+{
+ if (functionMetadata[index].used)
+ {
+ return;
+ }
+
+ functionMetadata[index].used = true;
+
+ for (int calleeIndex : mCallDag.getRecordFromIndex(index).callees)
+ {
+ internalTagUsedFunction(calleeIndex);
+ }
+}
+
+// A predicate for the stl that returns if a top-level node is unused
+class TCompiler::UnusedPredicate
+{
+ public:
+ UnusedPredicate(const CallDAG *callDag, const std::vector<FunctionMetadata> *metadatas)
+ : mCallDag(callDag),
+ mMetadatas(metadatas)
+ {
+ }
+
+ bool operator ()(TIntermNode *node)
+ {
+ const TIntermAggregate *asAggregate = node->getAsAggregate();
+
+ if (asAggregate == nullptr)
+ {
+ return false;
+ }
+
+ if (!(asAggregate->getOp() == EOpFunction || asAggregate->getOp() == EOpPrototype))
+ {
+ return false;
+ }
+
+ size_t callDagIndex = mCallDag->findIndex(asAggregate);
+ if (callDagIndex == CallDAG::InvalidIndex)
+ {
+ // This happens only for unimplemented prototypes which are thus unused
+ ASSERT(asAggregate->getOp() == EOpPrototype);
+ return true;
+ }
+
+ ASSERT(callDagIndex < mMetadatas->size());
+ return !(*mMetadatas)[callDagIndex].used;
+ }
+
+ private:
+ const CallDAG *mCallDag;
+ const std::vector<FunctionMetadata> *mMetadatas;
+};
+
+bool TCompiler::pruneUnusedFunctions(TIntermNode *root)
+{
+ TIntermAggregate *rootNode = root->getAsAggregate();
+ ASSERT(rootNode != nullptr);
+
+ UnusedPredicate isUnused(&mCallDag, &functionMetadata);
+ TIntermSequence *sequence = rootNode->getSequence();
+
+ if (!sequence->empty())
+ {
+ sequence->erase(std::remove_if(sequence->begin(), sequence->end(), isUnused), sequence->end());
+ }
+
+ return true;
}
bool TCompiler::validateOutputs(TIntermNode* root)
{
- ValidateOutputs validateOutputs(infoSink.info, compileResources.MaxDrawBuffers);
+ ValidateOutputs validateOutputs(getExtensionBehavior(), compileResources.MaxDrawBuffers);
root->traverse(&validateOutputs);
- return (validateOutputs.numErrors() == 0);
+ return (validateOutputs.validateAndCountErrors(infoSink.info) == 0);
}
void TCompiler::rewriteCSSShader(TIntermNode* root)
@@ -497,7 +701,7 @@ void TCompiler::rewriteCSSShader(TIntermNode* root)
bool TCompiler::validateLimitations(TIntermNode* root)
{
- ValidateLimitations validate(shaderType, infoSink.info);
+ ValidateLimitations validate(shaderType, &infoSink.info);
root->traverse(&validate);
return validate.numErrors() == 0;
}
@@ -543,17 +747,6 @@ bool TCompiler::limitExpressionComplexity(TIntermNode* root)
return false;
}
- TDependencyGraph graph(root);
-
- for (TFunctionCallVector::const_iterator iter = graph.beginUserDefinedFunctionCalls();
- iter != graph.endUserDefinedFunctionCalls();
- ++iter)
- {
- TGraphFunctionCall* samplerSymbol = *iter;
- TDependencyGraphTraverser graphTraverser;
- samplerSymbol->traverse(&graphTraverser);
- }
-
return true;
}
diff --git a/src/3rdparty/angle/src/compiler/translator/Compiler.h b/src/3rdparty/angle/src/compiler/translator/Compiler.h
index bcdb0d4c9d..c00a8f97aa 100644
--- a/src/3rdparty/angle/src/compiler/translator/Compiler.h
+++ b/src/3rdparty/angle/src/compiler/translator/Compiler.h
@@ -15,6 +15,7 @@
//
#include "compiler/translator/BuiltInFunctionEmulator.h"
+#include "compiler/translator/CallDAG.h"
#include "compiler/translator/ExtensionBehavior.h"
#include "compiler/translator/HashNames.h"
#include "compiler/translator/InfoSink.h"
@@ -36,6 +37,11 @@ class TranslatorHLSL;
bool IsWebGLBasedSpec(ShShaderSpec spec);
//
+// Helper function to check if the shader type is GLSL.
+//
+bool IsGLSL130OrNewer(ShShaderOutput output);
+
+//
// The base class used to back handles returned to the driver.
//
class TShHandleBase {
@@ -61,8 +67,8 @@ class TCompiler : public TShHandleBase
{
public:
TCompiler(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output);
- virtual ~TCompiler();
- virtual TCompiler* getAsCompiler() { return this; }
+ ~TCompiler() override;
+ TCompiler *getAsCompiler() override { return this; }
bool Init(const ShBuiltInResources& resources);
@@ -79,8 +85,11 @@ class TCompiler : public TShHandleBase
int getShaderVersion() const { return shaderVersion; }
TInfoSink& getInfoSink() { return infoSink; }
+ // Clears the results from the previous compilation.
+ void clearResults();
+
const std::vector<sh::Attribute> &getAttributes() const { return attributes; }
- const std::vector<sh::Attribute> &getOutputVariables() const { return outputVariables; }
+ const std::vector<sh::OutputVariable> &getOutputVariables() const { return outputVariables; }
const std::vector<sh::Uniform> &getUniforms() const { return uniforms; }
const std::vector<sh::Varying> &getVaryings() const { return varyings; }
const std::vector<sh::InterfaceBlock> &getInterfaceBlocks() const { return interfaceBlocks; }
@@ -92,6 +101,8 @@ class TCompiler : public TShHandleBase
ShShaderOutput getOutputType() const { return outputType; }
const std::string &getBuiltInResourcesString() const { return builtInResourcesString; }
+ bool shouldRunLoopAndIndexingValidation(int compileOptions) const;
+
// Get the resources set by InitBuiltInSymbolTable
const ShBuiltInResources& getResources() const;
@@ -101,10 +112,8 @@ class TCompiler : public TShHandleBase
bool InitBuiltInSymbolTable(const ShBuiltInResources& resources);
// Compute the string representation of the built-in resources
void setResourceString();
- // Clears the results from the previous compilation.
- void clearResults();
- // Return true if function recursion is detected or call depth exceeded.
- bool detectCallDepth(TIntermNode* root, TInfoSink& infoSink, bool limitCallStackDepth);
+ // Return false if the call depth is exceeded.
+ bool checkCallDepth();
// Returns true if a program has no conflicting or missing fragment outputs
bool validateOutputs(TIntermNode* root);
// Rewrites a shader's intermediate tree according to the CSS Shaders spec.
@@ -145,26 +154,57 @@ class TCompiler : public TShHandleBase
const char *getSourcePath() const;
const TPragma& getPragma() const { return mPragma; }
void writePragma();
+ unsigned int *getTemporaryIndex() { return &mTemporaryIndex; }
const ArrayBoundsClamper& getArrayBoundsClamper() const;
ShArrayIndexClampingStrategy getArrayIndexClampingStrategy() const;
const BuiltInFunctionEmulator& getBuiltInFunctionEmulator() const;
std::vector<sh::Attribute> attributes;
- std::vector<sh::Attribute> outputVariables;
+ std::vector<sh::OutputVariable> outputVariables;
std::vector<sh::Uniform> uniforms;
std::vector<sh::ShaderVariable> expandedUniforms;
std::vector<sh::Varying> varyings;
std::vector<sh::InterfaceBlock> interfaceBlocks;
+ virtual bool shouldCollectVariables(int compileOptions)
+ {
+ return (compileOptions & SH_VARIABLES) != 0;
+ }
+
private:
- TIntermNode *compileTreeImpl(const char* const shaderStrings[],
- size_t numStrings, int compileOptions);
+ // Creates the function call DAG for further analysis, returning false if there is a recursion
+ bool initCallDag(TIntermNode *root);
+ // Return false if "main" doesn't exist
+ bool tagUsedFunctions();
+ void internalTagUsedFunction(size_t index);
+
+ void initSamplerDefaultPrecision(TBasicType samplerType);
+
+ // Removes unused function declarations and prototypes from the AST
+ class UnusedPredicate;
+ bool pruneUnusedFunctions(TIntermNode *root);
+
+ TIntermNode *compileTreeImpl(const char *const shaderStrings[],
+ size_t numStrings,
+ const int compileOptions);
sh::GLenum shaderType;
ShShaderSpec shaderSpec;
ShShaderOutput outputType;
+ struct FunctionMetadata
+ {
+ FunctionMetadata()
+ : used(false)
+ {
+ }
+ bool used;
+ };
+
+ CallDAG mCallDag;
+ std::vector<FunctionMetadata> functionMetadata;
+
int maxUniformVectors;
int maxExpressionComplexity;
int maxCallStackDepth;
@@ -193,6 +233,8 @@ class TCompiler : public TShHandleBase
NameMap nameMap;
TPragma mPragma;
+
+ unsigned int mTemporaryIndex;
};
//
diff --git a/src/3rdparty/angle/src/compiler/translator/ConstantUnion.h b/src/3rdparty/angle/src/compiler/translator/ConstantUnion.h
index 31ff2ccfa7..a86d27f3ff 100644
--- a/src/3rdparty/angle/src/compiler/translator/ConstantUnion.h
+++ b/src/3rdparty/angle/src/compiler/translator/ConstantUnion.h
@@ -9,16 +9,18 @@
#include <assert.h>
-class ConstantUnion {
+#include "compiler/translator/BaseTypes.h"
+
+class TConstantUnion {
public:
POOL_ALLOCATOR_NEW_DELETE();
- ConstantUnion()
+ TConstantUnion()
{
iConst = 0;
type = EbtVoid;
}
- bool cast(TBasicType newType, const ConstantUnion &constant)
+ bool cast(TBasicType newType, const TConstantUnion &constant)
{
switch (newType)
{
@@ -109,7 +111,7 @@ public:
return b == bConst;
}
- bool operator==(const ConstantUnion& constant) const
+ bool operator==(const TConstantUnion& constant) const
{
if (constant.type != type)
return false;
@@ -148,12 +150,12 @@ public:
return !operator==(b);
}
- bool operator!=(const ConstantUnion& constant) const
+ bool operator!=(const TConstantUnion& constant) const
{
return !operator==(constant);
}
- bool operator>(const ConstantUnion& constant) const
+ bool operator>(const TConstantUnion& constant) const
{
assert(type == constant.type);
switch (type) {
@@ -168,7 +170,7 @@ public:
}
}
- bool operator<(const ConstantUnion& constant) const
+ bool operator<(const TConstantUnion& constant) const
{
assert(type == constant.type);
switch (type) {
@@ -183,9 +185,9 @@ public:
}
}
- ConstantUnion operator+(const ConstantUnion& constant) const
+ TConstantUnion operator+(const TConstantUnion& constant) const
{
- ConstantUnion returnValue;
+ TConstantUnion returnValue;
assert(type == constant.type);
switch (type) {
case EbtInt: returnValue.setIConst(iConst + constant.iConst); break;
@@ -197,9 +199,9 @@ public:
return returnValue;
}
- ConstantUnion operator-(const ConstantUnion& constant) const
+ TConstantUnion operator-(const TConstantUnion& constant) const
{
- ConstantUnion returnValue;
+ TConstantUnion returnValue;
assert(type == constant.type);
switch (type) {
case EbtInt: returnValue.setIConst(iConst - constant.iConst); break;
@@ -211,9 +213,9 @@ public:
return returnValue;
}
- ConstantUnion operator*(const ConstantUnion& constant) const
+ TConstantUnion operator*(const TConstantUnion& constant) const
{
- ConstantUnion returnValue;
+ TConstantUnion returnValue;
assert(type == constant.type);
switch (type) {
case EbtInt: returnValue.setIConst(iConst * constant.iConst); break;
@@ -225,9 +227,9 @@ public:
return returnValue;
}
- ConstantUnion operator%(const ConstantUnion& constant) const
+ TConstantUnion operator%(const TConstantUnion& constant) const
{
- ConstantUnion returnValue;
+ TConstantUnion returnValue;
assert(type == constant.type);
switch (type) {
case EbtInt: returnValue.setIConst(iConst % constant.iConst); break;
@@ -238,9 +240,9 @@ public:
return returnValue;
}
- ConstantUnion operator>>(const ConstantUnion& constant) const
+ TConstantUnion operator>>(const TConstantUnion& constant) const
{
- ConstantUnion returnValue;
+ TConstantUnion returnValue;
assert(type == constant.type);
switch (type) {
case EbtInt: returnValue.setIConst(iConst >> constant.iConst); break;
@@ -251,9 +253,9 @@ public:
return returnValue;
}
- ConstantUnion operator<<(const ConstantUnion& constant) const
+ TConstantUnion operator<<(const TConstantUnion& constant) const
{
- ConstantUnion returnValue;
+ TConstantUnion returnValue;
// 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.
@@ -267,9 +269,9 @@ public:
return returnValue;
}
- ConstantUnion operator&(const ConstantUnion& constant) const
+ TConstantUnion operator&(const TConstantUnion& constant) const
{
- ConstantUnion returnValue;
+ TConstantUnion returnValue;
assert(constant.type == EbtInt || constant.type == EbtUInt);
switch (type) {
case EbtInt: returnValue.setIConst(iConst & constant.iConst); break;
@@ -280,9 +282,9 @@ public:
return returnValue;
}
- ConstantUnion operator|(const ConstantUnion& constant) const
+ TConstantUnion operator|(const TConstantUnion& constant) const
{
- ConstantUnion returnValue;
+ TConstantUnion returnValue;
assert(type == constant.type);
switch (type) {
case EbtInt: returnValue.setIConst(iConst | constant.iConst); break;
@@ -293,9 +295,9 @@ public:
return returnValue;
}
- ConstantUnion operator^(const ConstantUnion& constant) const
+ TConstantUnion operator^(const TConstantUnion& constant) const
{
- ConstantUnion returnValue;
+ TConstantUnion returnValue;
assert(type == constant.type);
switch (type) {
case EbtInt: returnValue.setIConst(iConst ^ constant.iConst); break;
@@ -306,9 +308,9 @@ public:
return returnValue;
}
- ConstantUnion operator&&(const ConstantUnion& constant) const
+ TConstantUnion operator&&(const TConstantUnion& constant) const
{
- ConstantUnion returnValue;
+ TConstantUnion returnValue;
assert(type == constant.type);
switch (type) {
case EbtBool: returnValue.setBConst(bConst && constant.bConst); break;
@@ -318,9 +320,9 @@ public:
return returnValue;
}
- ConstantUnion operator||(const ConstantUnion& constant) const
+ TConstantUnion operator||(const TConstantUnion& constant) const
{
- ConstantUnion returnValue;
+ TConstantUnion returnValue;
assert(type == constant.type);
switch (type) {
case EbtBool: returnValue.setBConst(bConst || constant.bConst); break;
diff --git a/src/3rdparty/angle/src/compiler/translator/Diagnostics.cpp b/src/3rdparty/angle/src/compiler/translator/Diagnostics.cpp
index 92db3e55cf..593137fb0a 100644
--- a/src/3rdparty/angle/src/compiler/translator/Diagnostics.cpp
+++ b/src/3rdparty/angle/src/compiler/translator/Diagnostics.cpp
@@ -6,7 +6,7 @@
#include "compiler/translator/Diagnostics.h"
-#include "compiler/translator/compilerdebug.h"
+#include "common/debug.h"
#include "compiler/translator/InfoSink.h"
#include "compiler/preprocessor/SourceLocation.h"
@@ -50,11 +50,6 @@ void TDiagnostics::writeInfo(Severity severity,
sink << "'" << token << "' : " << reason << " " << extra << "\n";
}
-void TDiagnostics::writeDebug(const std::string& str)
-{
- mInfoSink.debug << str;
-}
-
void TDiagnostics::print(ID id,
const pp::SourceLocation& loc,
const std::string& text)
diff --git a/src/3rdparty/angle/src/compiler/translator/Diagnostics.h b/src/3rdparty/angle/src/compiler/translator/Diagnostics.h
index 078bc97772..bc26e4584f 100644
--- a/src/3rdparty/angle/src/compiler/translator/Diagnostics.h
+++ b/src/3rdparty/angle/src/compiler/translator/Diagnostics.h
@@ -16,7 +16,7 @@ class TDiagnostics : public pp::Diagnostics, angle::NonCopyable
{
public:
TDiagnostics(TInfoSink& infoSink);
- virtual ~TDiagnostics();
+ ~TDiagnostics() override;
TInfoSink& infoSink() { return mInfoSink; }
@@ -29,12 +29,8 @@ class TDiagnostics : public pp::Diagnostics, angle::NonCopyable
const std::string& token,
const std::string& extra);
- void writeDebug(const std::string& str);
-
protected:
- virtual void print(ID id,
- const pp::SourceLocation& loc,
- const std::string& text);
+ void print(ID id, const pp::SourceLocation &loc, const std::string &text) override;
private:
TInfoSink& mInfoSink;
diff --git a/src/3rdparty/angle/src/compiler/translator/DirectiveHandler.cpp b/src/3rdparty/angle/src/compiler/translator/DirectiveHandler.cpp
index 936c00a56c..ff8a69efa5 100644
--- a/src/3rdparty/angle/src/compiler/translator/DirectiveHandler.cpp
+++ b/src/3rdparty/angle/src/compiler/translator/DirectiveHandler.cpp
@@ -8,7 +8,8 @@
#include <sstream>
-#include "compiler/translator/compilerdebug.h"
+#include "angle_gl.h"
+#include "common/debug.h"
#include "compiler/translator/Diagnostics.h"
static TBehavior getBehavior(const std::string& str)
@@ -25,13 +26,15 @@ static TBehavior getBehavior(const std::string& str)
return EBhUndefined;
}
-TDirectiveHandler::TDirectiveHandler(TExtensionBehavior& extBehavior,
- TDiagnostics& diagnostics,
- int& shaderVersion,
+TDirectiveHandler::TDirectiveHandler(TExtensionBehavior &extBehavior,
+ TDiagnostics &diagnostics,
+ int &shaderVersion,
+ sh::GLenum shaderType,
bool debugShaderPrecisionSupported)
: mExtensionBehavior(extBehavior),
mDiagnostics(diagnostics),
mShaderVersion(shaderVersion),
+ mShaderType(shaderType),
mDebugShaderPrecisionSupported(debugShaderPrecisionSupported)
{
}
@@ -57,7 +60,16 @@ void TDirectiveHandler::handlePragma(const pp::SourceLocation& loc,
const char kAll[] = "all";
if (name == kInvariant && value == kAll)
+ {
+ if (mShaderVersion == 300 && mShaderType == GL_FRAGMENT_SHADER)
+ {
+ // ESSL 3.00.4 section 4.6.1
+ mDiagnostics.writeInfo(
+ pp::Diagnostics::PP_ERROR, loc,
+ "#pragma STDGL invariant(all) can not be used in fragment shader", name, value);
+ }
mPragma.stdgl.invariantAll = true;
+ }
// The STDGL pragma is used to reserve pragmas for use by future
// revisions of GLSL. Do not generate an error on unexpected
// name and value.
diff --git a/src/3rdparty/angle/src/compiler/translator/DirectiveHandler.h b/src/3rdparty/angle/src/compiler/translator/DirectiveHandler.h
index 2a81ee5707..00eb49114e 100644
--- a/src/3rdparty/angle/src/compiler/translator/DirectiveHandler.h
+++ b/src/3rdparty/angle/src/compiler/translator/DirectiveHandler.h
@@ -11,41 +11,42 @@
#include "compiler/translator/ExtensionBehavior.h"
#include "compiler/translator/Pragma.h"
#include "compiler/preprocessor/DirectiveHandlerBase.h"
+#include "GLSLANG/ShaderLang.h"
class TDiagnostics;
class TDirectiveHandler : public pp::DirectiveHandler, angle::NonCopyable
{
public:
- TDirectiveHandler(TExtensionBehavior& extBehavior,
- TDiagnostics& diagnostics,
- int& shaderVersion,
+ TDirectiveHandler(TExtensionBehavior &extBehavior,
+ TDiagnostics &diagnostics,
+ int &shaderVersion,
+ sh::GLenum shaderType,
bool debugShaderPrecisionSupported);
- virtual ~TDirectiveHandler();
+ ~TDirectiveHandler() override;
const TPragma& pragma() const { return mPragma; }
const TExtensionBehavior& extensionBehavior() const { return mExtensionBehavior; }
- virtual void handleError(const pp::SourceLocation& loc,
- const std::string& msg);
+ void handleError(const pp::SourceLocation &loc, const std::string &msg) override;
- virtual void handlePragma(const pp::SourceLocation& loc,
- const std::string& name,
- const std::string& value,
- bool stdgl);
+ void handlePragma(const pp::SourceLocation &loc,
+ const std::string &name,
+ const std::string &value,
+ bool stdgl) override;
- virtual void handleExtension(const pp::SourceLocation& loc,
- const std::string& name,
- const std::string& behavior);
+ void handleExtension(const pp::SourceLocation &loc,
+ const std::string &name,
+ const std::string &behavior) override;
- virtual void handleVersion(const pp::SourceLocation& loc,
- int version);
+ void handleVersion(const pp::SourceLocation &loc, int version) override;
private:
TPragma mPragma;
TExtensionBehavior& mExtensionBehavior;
TDiagnostics& mDiagnostics;
int& mShaderVersion;
+ sh::GLenum mShaderType;
bool mDebugShaderPrecisionSupported;
};
diff --git a/src/3rdparty/angle/src/compiler/translator/EmulatePrecision.cpp b/src/3rdparty/angle/src/compiler/translator/EmulatePrecision.cpp
index 697e042954..4a7fa54155 100644
--- a/src/3rdparty/angle/src/compiler/translator/EmulatePrecision.cpp
+++ b/src/3rdparty/angle/src/compiler/translator/EmulatePrecision.cpp
@@ -179,11 +179,50 @@ const char *getFloatTypeStr(const TType& type)
case 1:
return "float";
case 2:
- return type.getSecondarySize() > 1 ? "mat2" : "vec2";
+ switch(type.getSecondarySize())
+ {
+ case 1:
+ return "vec2";
+ case 2:
+ return "mat2";
+ case 3:
+ return "mat2x3";
+ case 4:
+ return "mat2x4";
+ default:
+ UNREACHABLE();
+ return NULL;
+ }
case 3:
- return type.getSecondarySize() > 1 ? "mat3" : "vec3";
+ switch(type.getSecondarySize())
+ {
+ case 1:
+ return "vec3";
+ case 2:
+ return "mat3x2";
+ case 3:
+ return "mat3";
+ case 4:
+ return "mat3x4";
+ default:
+ UNREACHABLE();
+ return NULL;
+ }
case 4:
- return type.getSecondarySize() > 1 ? "mat4" : "vec4";
+ switch(type.getSecondarySize())
+ {
+ case 1:
+ return "vec4";
+ case 2:
+ return "mat4x2";
+ case 3:
+ return "mat4x3";
+ case 4:
+ return "mat4";
+ default:
+ UNREACHABLE();
+ return NULL;
+ }
default:
UNREACHABLE();
return NULL;
@@ -199,8 +238,10 @@ bool canRoundFloat(const TType &type)
TIntermAggregate *createInternalFunctionCallNode(TString name, TIntermNode *child)
{
TIntermAggregate *callNode = new TIntermAggregate();
- callNode->setOp(EOpInternalFunctionCall);
- callNode->setName(name);
+ callNode->setOp(EOpFunctionCall);
+ TName nameObj(TFunction::mangleName(name));
+ nameObj.setInternal(true);
+ callNode->setNameObj(nameObj);
callNode->getSequence()->push_back(child);
return callNode;
}
@@ -252,17 +293,14 @@ bool parentUsesResult(TIntermNode* parent, TIntermNode* node)
} // namespace anonymous
-EmulatePrecision::EmulatePrecision()
- : TIntermTraverser(true, true, true),
- mDeclaringVariables(false),
- mInLValue(false),
- mInFunctionCallOutParameter(false)
+EmulatePrecision::EmulatePrecision(const TSymbolTable &symbolTable, int shaderVersion)
+ : TLValueTrackingTraverser(true, true, true, symbolTable, shaderVersion),
+ mDeclaringVariables(false)
{}
void EmulatePrecision::visitSymbol(TIntermSymbol *node)
{
- if (canRoundFloat(node->getType()) &&
- !mDeclaringVariables && !mInLValue && !mInFunctionCallOutParameter)
+ if (canRoundFloat(node->getType()) && !mDeclaringVariables && !isLValueRequiredHere())
{
TIntermNode *parent = getParentNode();
TIntermNode *replacement = createRoundingFunctionCallNode(node);
@@ -275,14 +313,6 @@ 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.
@@ -376,22 +406,9 @@ bool EmulatePrecision::visitAggregate(Visit visit, TIntermAggregate *node)
{
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:
@@ -418,50 +435,17 @@ bool EmulatePrecision::visitAggregate(Visit visit, TIntermAggregate *node)
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))
+ if (canRoundFloat(node->getType()) && !isInFunctionMap(node) &&
+ 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;
}
@@ -484,15 +468,10 @@ bool EmulatePrecision::visitUnary(Visit visit, TIntermUnary *node)
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)
@@ -511,7 +490,7 @@ void EmulatePrecision::writeEmulationHelpers(TInfoSinkBase& sink, ShShaderOutput
{
// Other languages not yet supported
ASSERT(outputLanguage == SH_GLSL_COMPATIBILITY_OUTPUT ||
- outputLanguage == SH_GLSL_CORE_OUTPUT ||
+ IsGLSL130OrNewer(outputLanguage) ||
outputLanguage == SH_ESSL_OUTPUT);
writeCommonPrecisionEmulationHelpers(sink, outputLanguage);
diff --git a/src/3rdparty/angle/src/compiler/translator/EmulatePrecision.h b/src/3rdparty/angle/src/compiler/translator/EmulatePrecision.h
index f1f560aa85..08177b3414 100644
--- a/src/3rdparty/angle/src/compiler/translator/EmulatePrecision.h
+++ b/src/3rdparty/angle/src/compiler/translator/EmulatePrecision.h
@@ -8,6 +8,7 @@
#define COMPILER_TRANSLATOR_EMULATE_PRECISION_H_
#include "common/angleutils.h"
+#include "compiler/translator/Compiler.h"
#include "compiler/translator/InfoSink.h"
#include "compiler/translator/IntermNode.h"
#include "GLSLANG/ShaderLang.h"
@@ -17,15 +18,15 @@
// need to write a huge number of variations of the emulated compound assignment
// to every translated shader with emulation enabled.
-class EmulatePrecision : public TIntermTraverser
+class EmulatePrecision : public TLValueTrackingTraverser
{
public:
- EmulatePrecision();
+ EmulatePrecision(const TSymbolTable &symbolTable, int shaderVersion);
- 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 visitSymbol(TIntermSymbol *node) override;
+ bool visitBinary(Visit visit, TIntermBinary *node) override;
+ bool visitUnary(Visit visit, TIntermUnary *node) override;
+ bool visitAggregate(Visit visit, TIntermAggregate *node) override;
void writeEmulationHelpers(TInfoSinkBase& sink, ShShaderOutput outputLanguage);
@@ -55,20 +56,7 @@ class EmulatePrecision : public TIntermTraverser
EmulationSet mEmulateCompoundMul;
EmulationSet mEmulateCompoundDiv;
- // Stack of function call parameter iterators
- std::vector<TIntermSequence::const_iterator> 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<TString, TIntermSequence*, TStringComparator> 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 cf4d7fba31..782c1c9217 100644
--- a/src/3rdparty/angle/src/compiler/translator/ExtensionBehavior.h
+++ b/src/3rdparty/angle/src/compiler/translator/ExtensionBehavior.h
@@ -34,4 +34,10 @@ inline const char* getBehaviorString(TBehavior b)
// Mapping between extension name and behavior.
typedef std::map<std::string, TBehavior> TExtensionBehavior;
+inline bool IsExtensionEnabled(const TExtensionBehavior &extBehavior, const char *extension)
+{
+ auto iter = extBehavior.find(extension);
+ return iter != extBehavior.end() && (iter->second == EBhEnable || iter->second == EBhRequire);
+}
+
#endif // COMPILER_TRANSLATOR_EXTENSIONBEHAVIOR_H_
diff --git a/src/3rdparty/angle/src/compiler/translator/ExtensionGLSL.cpp b/src/3rdparty/angle/src/compiler/translator/ExtensionGLSL.cpp
new file mode 100644
index 0000000000..d7f45f7eef
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/translator/ExtensionGLSL.cpp
@@ -0,0 +1,100 @@
+//
+// Copyright (c) 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.
+//
+// ExtensionGLSL.cpp: Implements the TExtensionGLSL class that tracks GLSL extension requirements
+// of shaders.
+
+#include "compiler/translator/ExtensionGLSL.h"
+
+#include "compiler/translator/VersionGLSL.h"
+
+TExtensionGLSL::TExtensionGLSL(ShShaderOutput output)
+ : TIntermTraverser(true, false, false), mTargetVersion(ShaderOutputTypeToGLSLVersion(output))
+{
+}
+
+const std::set<std::string> &TExtensionGLSL::getEnabledExtensions() const
+{
+ return mEnabledExtensions;
+}
+
+const std::set<std::string> &TExtensionGLSL::getRequiredExtensions() const
+{
+ return mRequiredExtensions;
+}
+
+bool TExtensionGLSL::visitUnary(Visit, TIntermUnary *node)
+{
+ checkOperator(node);
+
+ return true;
+}
+
+bool TExtensionGLSL::visitAggregate(Visit, TIntermAggregate *node)
+{
+ checkOperator(node);
+
+ return true;
+}
+
+void TExtensionGLSL::checkOperator(TIntermOperator *node)
+{
+ if (mTargetVersion < GLSL_VERSION_130)
+ {
+ return;
+ }
+
+ switch (node->getOp())
+ {
+ case EOpAbs:
+ break;
+
+ case EOpSign:
+ break;
+
+ case EOpMix:
+ break;
+
+ case EOpFloatBitsToInt:
+ case EOpFloatBitsToUint:
+ case EOpIntBitsToFloat:
+ case EOpUintBitsToFloat:
+ if (mTargetVersion < GLSL_VERSION_330)
+ {
+ // Bit conversion functions cannot be emulated.
+ mRequiredExtensions.insert("GL_ARB_shader_bit_encoding");
+ }
+ break;
+
+ case EOpPackSnorm2x16:
+ case EOpPackHalf2x16:
+ case EOpUnpackSnorm2x16:
+ case EOpUnpackHalf2x16:
+ if (mTargetVersion < GLSL_VERSION_420)
+ {
+ mEnabledExtensions.insert("GL_ARB_shading_language_packing");
+
+ if (mTargetVersion < GLSL_VERSION_330)
+ {
+ // floatBitsToUint and uintBitsToFloat are needed to emulate
+ // packHalf2x16 and unpackHalf2x16 respectively and cannot be
+ // emulated themselves.
+ mRequiredExtensions.insert("GL_ARB_shader_bit_encoding");
+ }
+ }
+ break;
+
+ case EOpPackUnorm2x16:
+ case EOpUnpackUnorm2x16:
+ if (mTargetVersion < GLSL_VERSION_410)
+ {
+ mEnabledExtensions.insert("GL_ARB_shading_language_packing");
+ }
+ break;
+
+ default:
+ break;
+ }
+}
diff --git a/src/3rdparty/angle/src/compiler/translator/ExtensionGLSL.h b/src/3rdparty/angle/src/compiler/translator/ExtensionGLSL.h
new file mode 100644
index 0000000000..6bb84d612d
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/translator/ExtensionGLSL.h
@@ -0,0 +1,39 @@
+//
+// Copyright (c) 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.
+//
+// ExtensionGLSL.h: Defines the TExtensionGLSL class that tracks GLSL extension requirements of
+// shaders.
+
+#ifndef COMPILER_TRANSLATOR_EXTENSIONGLSL_H_
+#define COMPILER_TRANSLATOR_EXTENSIONGLSL_H_
+
+#include <set>
+#include <string>
+
+#include "compiler/translator/IntermNode.h"
+
+// Traverses the intermediate tree to determine which GLSL extensions are required
+// to support the shader.
+class TExtensionGLSL : public TIntermTraverser
+{
+ public:
+ TExtensionGLSL(ShShaderOutput output);
+
+ const std::set<std::string> &getEnabledExtensions() const;
+ const std::set<std::string> &getRequiredExtensions() const;
+
+ bool visitUnary(Visit visit, TIntermUnary *node) override;
+ bool visitAggregate(Visit visit, TIntermAggregate *node) override;
+
+ private:
+ void checkOperator(TIntermOperator *node);
+
+ int mTargetVersion;
+
+ std::set<std::string> mEnabledExtensions;
+ std::set<std::string> mRequiredExtensions;
+};
+
+#endif // COMPILER_TRANSLATOR_EXTENSIONGLSL_H_
diff --git a/src/3rdparty/angle/src/compiler/translator/FlagStd140Structs.h b/src/3rdparty/angle/src/compiler/translator/FlagStd140Structs.h
index 07b9a72c5c..cfcd775af7 100644
--- a/src/3rdparty/angle/src/compiler/translator/FlagStd140Structs.h
+++ b/src/3rdparty/angle/src/compiler/translator/FlagStd140Structs.h
@@ -18,11 +18,17 @@ namespace sh
class FlagStd140Structs : public TIntermTraverser
{
public:
+
+ FlagStd140Structs()
+ : TIntermTraverser(true, false, false)
+ {
+ }
+
const std::vector<TIntermTyped *> getFlaggedNodes() const { return mFlaggedNodes; }
protected:
- virtual bool visitBinary(Visit visit, TIntermBinary *binaryNode);
- virtual void visitSymbol(TIntermSymbol *symbol);
+ bool visitBinary(Visit visit, TIntermBinary *binaryNode) override;
+ void visitSymbol(TIntermSymbol *symbol) override;
private:
bool isInStd140InterfaceBlock(TIntermTyped *node) const;
diff --git a/src/3rdparty/angle/src/compiler/translator/ForLoopUnroll.cpp b/src/3rdparty/angle/src/compiler/translator/ForLoopUnroll.cpp
index f3be20d978..4cc1c26a13 100644
--- a/src/3rdparty/angle/src/compiler/translator/ForLoopUnroll.cpp
+++ b/src/3rdparty/angle/src/compiler/translator/ForLoopUnroll.cpp
@@ -6,6 +6,9 @@
#include "compiler/translator/ForLoopUnroll.h"
+#include "compiler/translator/ValidateLimitations.h"
+#include "angle_gl.h"
+
bool ForLoopUnrollMarker::visitBinary(Visit, TIntermBinary *node)
{
if (mUnrollCondition != kSamplerArrayIndex)
@@ -38,11 +41,16 @@ bool ForLoopUnrollMarker::visitBinary(Visit, TIntermBinary *node)
bool ForLoopUnrollMarker::visitLoop(Visit, TIntermLoop *node)
{
- if (mUnrollCondition == kIntegerIndex)
+ bool canBeUnrolled = mHasRunLoopValidation;
+ if (!mHasRunLoopValidation)
+ {
+ canBeUnrolled = ValidateLimitations::IsLimitedForLoop(node);
+ }
+ if (mUnrollCondition == kIntegerIndex && canBeUnrolled)
{
// Check if loop index type is integer.
- // This is called after ValidateLimitations pass, so all the calls
- // should be valid. See ValidateLimitations::validateForLoopInit().
+ // This is called after ValidateLimitations pass, so the loop has the limited form specified
+ // in ESSL 1.00 appendix A.
TIntermSequence *declSeq = node->getInit()->getAsAggregate()->getSequence();
TIntermSymbol *symbol = (*declSeq)[0]->getAsBinaryNode()->getLeft()->getAsSymbolNode();
if (symbol->getBasicType() == EbtInt)
@@ -50,11 +58,18 @@ bool ForLoopUnrollMarker::visitLoop(Visit, TIntermLoop *node)
}
TIntermNode *body = node->getBody();
- if (body != NULL)
+ if (body != nullptr)
{
- mLoopStack.push(node);
- body->traverse(this);
- mLoopStack.pop();
+ if (canBeUnrolled)
+ {
+ mLoopStack.push(node);
+ body->traverse(this);
+ mLoopStack.pop();
+ }
+ else
+ {
+ body->traverse(this);
+ }
}
// The loop is fully processed - no need to visit children.
return false;
diff --git a/src/3rdparty/angle/src/compiler/translator/ForLoopUnroll.h b/src/3rdparty/angle/src/compiler/translator/ForLoopUnroll.h
index c8787d55a0..9c49ecad33 100644
--- a/src/3rdparty/angle/src/compiler/translator/ForLoopUnroll.h
+++ b/src/3rdparty/angle/src/compiler/translator/ForLoopUnroll.h
@@ -24,16 +24,18 @@ class ForLoopUnrollMarker : public TIntermTraverser
kSamplerArrayIndex
};
- ForLoopUnrollMarker(UnrollCondition condition)
- : mUnrollCondition(condition),
+ ForLoopUnrollMarker(UnrollCondition condition, bool hasRunLoopValidation)
+ : TIntermTraverser(true, false, false),
+ mUnrollCondition(condition),
mSamplerArrayIndexIsFloatLoopIndex(false),
- mVisitSamplerArrayIndexNodeInsideLoop(false)
+ mVisitSamplerArrayIndexNodeInsideLoop(false),
+ mHasRunLoopValidation(hasRunLoopValidation)
{
}
- virtual bool visitBinary(Visit, TIntermBinary *node);
- virtual bool visitLoop(Visit, TIntermLoop *node);
- virtual void visitSymbol(TIntermSymbol *node);
+ bool visitBinary(Visit, TIntermBinary *node) override;
+ bool visitLoop(Visit, TIntermLoop *node) override;
+ void visitSymbol(TIntermSymbol *node) override;
bool samplerArrayIndexIsFloatLoopIndex() const
{
@@ -45,6 +47,7 @@ class ForLoopUnrollMarker : public TIntermTraverser
TLoopStack mLoopStack;
bool mSamplerArrayIndexIsFloatLoopIndex;
bool mVisitSamplerArrayIndexNodeInsideLoop;
+ bool mHasRunLoopValidation;
};
#endif // COMPILER_TRANSLATOR_FORLOOPUNROLL_H_
diff --git a/src/3rdparty/angle/src/compiler/translator/Initialize.cpp b/src/3rdparty/angle/src/compiler/translator/Initialize.cpp
index 9e11405758..2f51aada7f 100644
--- a/src/3rdparty/angle/src/compiler/translator/Initialize.cpp
+++ b/src/3rdparty/angle/src/compiler/translator/Initialize.cpp
@@ -11,25 +11,26 @@
//
#include "compiler/translator/Initialize.h"
+#include "compiler/translator/Cache.h"
#include "compiler/translator/IntermNode.h"
#include "angle_gl.h"
void InsertBuiltInFunctions(sh::GLenum type, ShShaderSpec spec, const ShBuiltInResources &resources, TSymbolTable &symbolTable)
{
- TType *float1 = new TType(EbtFloat);
- 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 *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);
+ const TType *float1 = TCache::getType(EbtFloat);
+ const TType *float2 = TCache::getType(EbtFloat, 2);
+ const TType *float3 = TCache::getType(EbtFloat, 3);
+ const TType *float4 = TCache::getType(EbtFloat, 4);
+ const TType *int1 = TCache::getType(EbtInt);
+ const TType *int2 = TCache::getType(EbtInt, 2);
+ const TType *int3 = TCache::getType(EbtInt, 3);
+ const TType *uint1 = TCache::getType(EbtUInt);
+ const TType *bool1 = TCache::getType(EbtBool);
+ const TType *genType = TCache::getType(EbtGenType);
+ const TType *genIType = TCache::getType(EbtGenIType);
+ const TType *genUType = TCache::getType(EbtGenUType);
+ const TType *genBType = TCache::getType(EbtGenBType);
//
// Angle and Trigonometric Functions.
@@ -96,19 +97,16 @@ void InsertBuiltInFunctions(sh::GLenum type, ShShaderSpec spec, const ShBuiltInR
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(ESSL3_BUILTINS, EOpMix, genType, "mix", genType, genType, genBType);
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);
+ const TType *outFloat1 = TCache::getType(EbtFloat, EvqOut);
+ const TType *outFloat2 = TCache::getType(EbtFloat, EvqOut, 2);
+ const TType *outFloat3 = TCache::getType(EbtFloat, EvqOut, 3);
+ const TType *outFloat4 = TCache::getType(EbtFloat, EvqOut, 4);
symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpModf, float1, "modf", float1, outFloat1);
symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpModf, float2, "modf", float2, outFloat2);
@@ -141,15 +139,15 @@ void InsertBuiltInFunctions(sh::GLenum type, ShShaderSpec spec, const ShBuiltInR
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);
+ const TType *mat2 = TCache::getType(EbtFloat, 2, 2);
+ const TType *mat3 = TCache::getType(EbtFloat, 3, 3);
+ const TType *mat4 = TCache::getType(EbtFloat, 4, 4);
+ const TType *mat2x3 = TCache::getType(EbtFloat, 2, 3);
+ const TType *mat3x2 = TCache::getType(EbtFloat, 3, 2);
+ const TType *mat2x4 = TCache::getType(EbtFloat, 2, 4);
+ const TType *mat4x2 = TCache::getType(EbtFloat, 4, 2);
+ const TType *mat3x4 = TCache::getType(EbtFloat, 3, 4);
+ const TType *mat4x3 = TCache::getType(EbtFloat, 4, 3);
//
// Matrix Functions.
@@ -192,10 +190,10 @@ void InsertBuiltInFunctions(sh::GLenum type, ShShaderSpec spec, const ShBuiltInR
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);
+ const TType *vec = TCache::getType(EbtVec);
+ const TType *ivec = TCache::getType(EbtIVec);
+ const TType *uvec = TCache::getType(EbtUVec);
+ const TType *bvec = TCache::getType(EbtBVec);
//
// Vector relational functions.
@@ -224,8 +222,8 @@ void InsertBuiltInFunctions(sh::GLenum type, ShShaderSpec spec, const ShBuiltInR
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);
+ const TType *sampler2D = TCache::getType(EbtSampler2D);
+ const TType *samplerCube = TCache::getType(EbtSamplerCube);
//
// Texture Functions for GLSL ES 1.0
@@ -237,7 +235,7 @@ void InsertBuiltInFunctions(sh::GLenum type, ShShaderSpec spec, const ShBuiltInR
if (resources.OES_EGL_image_external)
{
- TType *samplerExternalOES = new TType(EbtSamplerExternalOES);
+ const TType *samplerExternalOES = TCache::getType(EbtSamplerExternalOES);
symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2D", samplerExternalOES, float2);
symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DProj", samplerExternalOES, float3);
@@ -246,7 +244,7 @@ void InsertBuiltInFunctions(sh::GLenum type, ShShaderSpec spec, const ShBuiltInR
if (resources.ARB_texture_rectangle)
{
- TType *sampler2DRect = new TType(EbtSampler2DRect);
+ const TType *sampler2DRect = TCache::getType(EbtSampler2DRect);
symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DRect", sampler2DRect, float2);
symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DRectProj", sampler2DRect, float3);
@@ -295,12 +293,12 @@ void InsertBuiltInFunctions(sh::GLenum type, ShShaderSpec spec, const ShBuiltInR
symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "textureCubeLod", samplerCube, float3, float1);
}
- TType *gvec4 = new TType(EbtGVec4);
+ const TType *gvec4 = TCache::getType(EbtGVec4);
- TType *gsampler2D = new TType(EbtGSampler2D);
- TType *gsamplerCube = new TType(EbtGSamplerCube);
- TType *gsampler3D = new TType(EbtGSampler3D);
- TType *gsampler2DArray = new TType(EbtGSampler2DArray);
+ const TType *gsampler2D = TCache::getType(EbtGSampler2D);
+ const TType *gsamplerCube = TCache::getType(EbtGSamplerCube);
+ const TType *gsampler3D = TCache::getType(EbtGSampler3D);
+ const TType *gsampler2DArray = TCache::getType(EbtGSampler2DArray);
//
// Texture Functions for GLSL ES 3.0
@@ -328,9 +326,9 @@ void InsertBuiltInFunctions(sh::GLenum type, ShShaderSpec spec, const ShBuiltInR
symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProj", gsampler3D, float4, float1);
}
- TType *sampler2DShadow = new TType(EbtSampler2DShadow);
- TType *samplerCubeShadow = new TType(EbtSamplerCubeShadow);
- TType *sampler2DArrayShadow = new TType(EbtSampler2DArrayShadow);
+ const TType *sampler2DShadow = TCache::getType(EbtSampler2DShadow);
+ const TType *samplerCubeShadow = TCache::getType(EbtSamplerCubeShadow);
+ const TType *sampler2DArrayShadow = TCache::getType(EbtSampler2DArrayShadow);
symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "texture", sampler2DShadow, float3);
symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "texture", samplerCubeShadow, float4);
@@ -466,6 +464,12 @@ void InsertBuiltInFunctions(sh::GLenum type, ShShaderSpec spec, const ShBuiltInR
if (spec != SH_CSS_SHADERS_SPEC)
{
symbolTable.insertConstInt(COMMON_BUILTINS, "gl_MaxDrawBuffers", resources.MaxDrawBuffers);
+ if (resources.EXT_blend_func_extended)
+ {
+ symbolTable.insertConstIntExt(COMMON_BUILTINS, "GL_EXT_blend_func_extended",
+ "gl_MaxDualSourceDrawBuffersEXT",
+ resources.MaxDualSourceDrawBuffers);
+ }
}
symbolTable.insertConstInt(ESSL3_BUILTINS, "gl_MaxVertexOutputVectors", resources.MaxVertexOutputVectors);
@@ -504,12 +508,33 @@ void IdentifyBuiltIns(sh::GLenum type, ShShaderSpec spec,
fragData.setArraySize(resources.MaxDrawBuffers);
symbolTable.insert(ESSL1_BUILTINS, new TVariable(NewPoolTString("gl_FragData"), fragData));
+ if (resources.EXT_blend_func_extended)
+ {
+ symbolTable.insert(
+ ESSL1_BUILTINS, "GL_EXT_blend_func_extended",
+ new TVariable(NewPoolTString("gl_SecondaryFragColorEXT"),
+ TType(EbtFloat, EbpMedium, EvqSecondaryFragColorEXT, 4)));
+ TType secondaryFragData(EbtFloat, EbpMedium, EvqSecondaryFragDataEXT, 4, 1, true);
+ secondaryFragData.setArraySize(resources.MaxDualSourceDrawBuffers);
+ symbolTable.insert(
+ ESSL1_BUILTINS, "GL_EXT_blend_func_extended",
+ new TVariable(NewPoolTString("gl_SecondaryFragDataEXT"), secondaryFragData));
+ }
+
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.insert(
+ ESSL1_BUILTINS, "GL_EXT_frag_depth",
+ new TVariable(
+ NewPoolTString("gl_FragDepthEXT"),
+ TType(EbtFloat, resources.FragmentPrecisionHigh ? EbpHigh : EbpMedium,
+ EvqFragDepthEXT, 1)));
}
+ symbolTable.insert(ESSL3_BUILTINS,
+ new TVariable(NewPoolTString("gl_FragDepth"),
+ TType(EbtFloat, EbpHigh, EvqFragDepth, 1)));
+
if (resources.EXT_shader_framebuffer_fetch || resources.NV_shader_framebuffer_fetch)
{
TType lastFragData(EbtFloat, EbpMedium, EvqLastFragData, 4, 1, true);
@@ -569,6 +594,8 @@ void InitExtensionBehavior(const ShBuiltInResources& resources,
extBehavior["GL_OES_EGL_image_external"] = EBhUndefined;
if (resources.ARB_texture_rectangle)
extBehavior["GL_ARB_texture_rectangle"] = EBhUndefined;
+ if (resources.EXT_blend_func_extended)
+ extBehavior["GL_EXT_blend_func_extended"] = EBhUndefined;
if (resources.EXT_draw_buffers)
extBehavior["GL_EXT_draw_buffers"] = EBhUndefined;
if (resources.EXT_frag_depth)
diff --git a/src/3rdparty/angle/src/compiler/translator/InitializeDll.cpp b/src/3rdparty/angle/src/compiler/translator/InitializeDll.cpp
index c98430662a..713965389f 100644
--- a/src/3rdparty/angle/src/compiler/translator/InitializeDll.cpp
+++ b/src/3rdparty/angle/src/compiler/translator/InitializeDll.cpp
@@ -4,6 +4,7 @@
// found in the LICENSE file.
//
+#include "compiler/translator/Cache.h"
#include "compiler/translator/InitializeDll.h"
#include "compiler/translator/InitializeGlobals.h"
#include "compiler/translator/InitializeParseContext.h"
@@ -24,6 +25,8 @@ bool InitProcess()
return false;
}
+ TCache::initialize();
+
return true;
}
@@ -31,4 +34,5 @@ void DetachProcess()
{
FreeParseContextIndex();
FreePoolIndex();
+ TCache::destroy();
}
diff --git a/src/3rdparty/angle/src/compiler/translator/InitializeParseContext.h b/src/3rdparty/angle/src/compiler/translator/InitializeParseContext.h
index fa9b885e80..70dac702e2 100644
--- a/src/3rdparty/angle/src/compiler/translator/InitializeParseContext.h
+++ b/src/3rdparty/angle/src/compiler/translator/InitializeParseContext.h
@@ -10,7 +10,7 @@
bool InitializeParseContextIndex();
void FreeParseContextIndex();
-struct TParseContext;
+class TParseContext;
extern void SetGlobalParseContext(TParseContext* context);
extern TParseContext* GetGlobalParseContext();
diff --git a/src/3rdparty/angle/src/compiler/translator/InitializeVariables.cpp b/src/3rdparty/angle/src/compiler/translator/InitializeVariables.cpp
index 0e3e2ebe55..86d3e6bc83 100644
--- a/src/3rdparty/angle/src/compiler/translator/InitializeVariables.cpp
+++ b/src/3rdparty/angle/src/compiler/translator/InitializeVariables.cpp
@@ -5,7 +5,8 @@
//
#include "compiler/translator/InitializeVariables.h"
-#include "compiler/translator/compilerdebug.h"
+
+#include "common/debug.h"
namespace
{
@@ -13,10 +14,10 @@ namespace
TIntermConstantUnion *constructFloatConstUnionNode(const TType &type)
{
TType myType = type;
- unsigned char size = myType.getNominalSize();
+ unsigned char size = static_cast<unsigned char>(myType.getNominalSize());
if (myType.isMatrix())
size *= size;
- ConstantUnion *u = new ConstantUnion[size];
+ TConstantUnion *u = new TConstantUnion[size];
for (int ii = 0; ii < size; ++ii)
u[ii].setFConst(0.0f);
@@ -28,7 +29,7 @@ TIntermConstantUnion *constructFloatConstUnionNode(const TType &type)
TIntermConstantUnion *constructIndexNode(int index)
{
- ConstantUnion *u = new ConstantUnion[1];
+ TConstantUnion *u = new TConstantUnion[1];
u[0].setIConst(index);
TType type(EbtInt, EbpUndefined, EvqConst, 1);
diff --git a/src/3rdparty/angle/src/compiler/translator/InitializeVariables.h b/src/3rdparty/angle/src/compiler/translator/InitializeVariables.h
index 4a81266498..2a141ec91c 100644
--- a/src/3rdparty/angle/src/compiler/translator/InitializeVariables.h
+++ b/src/3rdparty/angle/src/compiler/translator/InitializeVariables.h
@@ -26,19 +26,20 @@ class InitializeVariables : public TIntermTraverser
typedef TVector<InitVariableInfo> InitVariableInfoList;
InitializeVariables(const InitVariableInfoList &vars)
- : mCodeInserted(false),
- mVariables(vars)
+ : TIntermTraverser(true, false, false),
+ mVariables(vars),
+ mCodeInserted(false)
{
}
protected:
- virtual bool visitBinary(Visit, TIntermBinary *node) { return false; }
- virtual bool visitUnary(Visit, TIntermUnary *node) { return false; }
- virtual bool visitSelection(Visit, TIntermSelection *node) { return false; }
- virtual bool visitLoop(Visit, TIntermLoop *node) { return false; }
- virtual bool visitBranch(Visit, TIntermBranch *node) { return false; }
+ bool visitBinary(Visit, TIntermBinary *node) override { return false; }
+ bool visitUnary(Visit, TIntermUnary *node) override { return false; }
+ bool visitSelection(Visit, TIntermSelection *node) override { return false; }
+ bool visitLoop(Visit, TIntermLoop *node) override { return false; }
+ bool visitBranch(Visit, TIntermBranch *node) override { return false; }
- virtual bool visitAggregate(Visit visit, TIntermAggregate* node);
+ bool visitAggregate(Visit visit, TIntermAggregate *node) override;
private:
void insertInitCode(TIntermSequence *sequence);
diff --git a/src/3rdparty/angle/src/compiler/translator/IntermNode.cpp b/src/3rdparty/angle/src/compiler/translator/IntermNode.cpp
index 266e3c8e3d..2a92860088 100644
--- a/src/3rdparty/angle/src/compiler/translator/IntermNode.cpp
+++ b/src/3rdparty/angle/src/compiler/translator/IntermNode.cpp
@@ -10,8 +10,13 @@
#include <float.h>
#include <limits.h>
+#include <math.h>
+#include <stdlib.h>
#include <algorithm>
+#include <vector>
+#include "common/mathutil.h"
+#include "common/matrix_utils.h"
#include "compiler/translator/HashNames.h"
#include "compiler/translator/IntermNode.h"
#include "compiler/translator/SymbolTable.h"
@@ -19,6 +24,10 @@
namespace
{
+const float kPi = 3.14159265358979323846f;
+const float kDegreesToRadiansMultiplier = kPi / 180.0f;
+const float kRadiansToDegreesMultiplier = 180.0f / kPi;
+
TPrecision GetHigherPrecision(TPrecision left, TPrecision right)
{
return left > right ? left : right;
@@ -57,71 +66,107 @@ bool ValidateMultiplication(TOperator op, const TType &left, const TType &right)
}
}
-bool CompareStructure(const TType& leftNodeType,
- ConstantUnion *rightUnionArray,
- ConstantUnion *leftUnionArray);
-
-bool CompareStruct(const TType &leftNodeType,
- ConstantUnion *rightUnionArray,
- ConstantUnion *leftUnionArray)
+TConstantUnion *Vectorize(const TConstantUnion &constant, size_t size)
{
- const TFieldList &fields = leftNodeType.getStruct()->fields();
+ TConstantUnion *constUnion = new TConstantUnion[size];
+ for (unsigned int i = 0; i < size; ++i)
+ constUnion[i] = constant;
+
+ return constUnion;
+}
- size_t structSize = fields.size();
- size_t index = 0;
+void UndefinedConstantFoldingError(const TSourceLoc &loc, TOperator op, TBasicType basicType,
+ TInfoSink &infoSink, TConstantUnion *result)
+{
+ std::stringstream constantFoldingErrorStream;
+ constantFoldingErrorStream << "'" << GetOperatorString(op)
+ << "' operation result is undefined for the values passed in";
+ infoSink.info.message(EPrefixWarning, loc, constantFoldingErrorStream.str().c_str());
- for (size_t j = 0; j < structSize; j++)
+ switch (basicType)
{
- size_t size = fields[j]->type()->getObjectSize();
- for (size_t i = 0; i < size; i++)
- {
- if (fields[j]->type()->getBasicType() == EbtStruct)
- {
- if (!CompareStructure(*fields[j]->type(),
- &rightUnionArray[index],
- &leftUnionArray[index]))
- {
- return false;
- }
- }
- else
- {
- if (leftUnionArray[index] != rightUnionArray[index])
- return false;
- index++;
- }
- }
+ case EbtFloat :
+ result->setFConst(0.0f);
+ break;
+ case EbtInt:
+ result->setIConst(0);
+ break;
+ case EbtUInt:
+ result->setUConst(0u);
+ break;
+ case EbtBool:
+ result->setBConst(false);
+ break;
+ default:
+ break;
}
- return true;
}
-bool CompareStructure(const TType &leftNodeType,
- ConstantUnion *rightUnionArray,
- ConstantUnion *leftUnionArray)
+float VectorLength(const TConstantUnion *paramArray, size_t paramArraySize)
{
- if (leftNodeType.isArray())
+ float result = 0.0f;
+ for (size_t i = 0; i < paramArraySize; i++)
{
- TType typeWithoutArrayness = leftNodeType;
- typeWithoutArrayness.clearArrayness();
+ float f = paramArray[i].getFConst();
+ result += f * f;
+ }
+ return sqrtf(result);
+}
- size_t arraySize = leftNodeType.getArraySize();
+float VectorDotProduct(const TConstantUnion *paramArray1,
+ const TConstantUnion *paramArray2,
+ size_t paramArraySize)
+{
+ float result = 0.0f;
+ for (size_t i = 0; i < paramArraySize; i++)
+ result += paramArray1[i].getFConst() * paramArray2[i].getFConst();
+ return result;
+}
- for (size_t i = 0; i < arraySize; ++i)
- {
- size_t offset = typeWithoutArrayness.getObjectSize() * i;
- if (!CompareStruct(typeWithoutArrayness,
- &rightUnionArray[offset],
- &leftUnionArray[offset]))
- {
- return false;
- }
- }
- }
- else
+TIntermTyped *CreateFoldedNode(TConstantUnion *constArray,
+ const TIntermTyped *originalNode,
+ TQualifier qualifier)
+{
+ if (constArray == nullptr)
{
- return CompareStruct(leftNodeType, rightUnionArray, leftUnionArray);
+ return nullptr;
}
- return true;
+ TIntermTyped *folded = new TIntermConstantUnion(constArray, originalNode->getType());
+ folded->getTypePointer()->setQualifier(qualifier);
+ folded->setLine(originalNode->getLine());
+ return folded;
+}
+
+angle::Matrix<float> GetMatrix(const TConstantUnion *paramArray,
+ const unsigned int &rows,
+ const unsigned int &cols)
+{
+ std::vector<float> elements;
+ for (size_t i = 0; i < rows * cols; i++)
+ elements.push_back(paramArray[i].getFConst());
+ // Transpose is used since the Matrix constructor expects arguments in row-major order,
+ // whereas the paramArray is in column-major order.
+ return angle::Matrix<float>(elements, rows, cols).transpose();
+}
+
+angle::Matrix<float> GetMatrix(const TConstantUnion *paramArray, const unsigned int &size)
+{
+ std::vector<float> elements;
+ for (size_t i = 0; i < size * size; i++)
+ elements.push_back(paramArray[i].getFConst());
+ // Transpose is used since the Matrix constructor expects arguments in row-major order,
+ // whereas the paramArray is in column-major order.
+ return angle::Matrix<float>(elements, size).transpose();
+}
+
+void SetUnionArrayFromMatrix(const angle::Matrix<float> &m, TConstantUnion *resultArray)
+{
+ // Transpose is used since the input Matrix is in row-major order,
+ // whereas the actual result should be in column-major order.
+ angle::Matrix<float> result = m.transpose();
+ std::vector<float> resultElements = result.elements();
+ for (size_t i = 0; i < resultElements.size(); i++)
+ resultArray[i].setFConst(resultElements[i]);
}
} // namespace anonymous
@@ -153,7 +198,7 @@ bool TIntermLoop::replaceChildNode(
REPLACE_IF_IS(mInit, TIntermNode, original, replacement);
REPLACE_IF_IS(mCond, TIntermTyped, original, replacement);
REPLACE_IF_IS(mExpr, TIntermTyped, original, replacement);
- REPLACE_IF_IS(mBody, TIntermNode, original, replacement);
+ REPLACE_IF_IS(mBody, TIntermAggregate, original, replacement);
return false;
}
@@ -189,8 +234,47 @@ bool TIntermAggregate::replaceChildNode(
return false;
}
+bool TIntermAggregate::replaceChildNodeWithMultiple(TIntermNode *original, TIntermSequence replacements)
+{
+ for (auto it = mSequence.begin(); it < mSequence.end(); ++it)
+ {
+ if (*it == original)
+ {
+ it = mSequence.erase(it);
+ mSequence.insert(it, replacements.begin(), replacements.end());
+ return true;
+ }
+ }
+ return false;
+}
+
+bool TIntermAggregate::insertChildNodes(TIntermSequence::size_type position, TIntermSequence insertions)
+{
+ if (position > mSequence.size())
+ {
+ return false;
+ }
+ auto it = mSequence.begin() + position;
+ mSequence.insert(it, insertions.begin(), insertions.end());
+ return true;
+}
+
+bool TIntermAggregate::areChildrenConstQualified()
+{
+ for (TIntermNode *&child : mSequence)
+ {
+ TIntermTyped *typed = child->getAsTyped();
+ if (typed && typed->getQualifier() != EvqConst)
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
void TIntermAggregate::setPrecisionFromChildren()
{
+ mGotPrecisionFromChildren = true;
if (getBasicType() == EbtBool)
{
mType.setPrecision(EbpUndefined);
@@ -229,7 +313,7 @@ void TIntermAggregate::setBuiltInFunctionPrecision()
}
// ESSL 3.0 spec section 8: textureSize always gets highp precision.
// All other functions that take a sampler are assumed to be texture functions.
- if (mName.find("textureSize") == 0)
+ if (mName.getString().find("textureSize") == 0)
mType.setPrecision(EbpHigh);
else
mType.setPrecision(precision);
@@ -259,6 +343,70 @@ bool TIntermCase::replaceChildNode(
return false;
}
+TIntermTyped::TIntermTyped(const TIntermTyped &node) : TIntermNode(), mType(node.mType)
+{
+ // Copy constructor is disallowed for TIntermNode in order to disallow it for subclasses that
+ // don't explicitly allow it, so normal TIntermNode constructor is used to construct the copy.
+ // We need to manually copy any fields of TIntermNode besides handling fields in TIntermTyped.
+ mLine = node.mLine;
+}
+
+TIntermConstantUnion::TIntermConstantUnion(const TIntermConstantUnion &node) : TIntermTyped(node)
+{
+ mUnionArrayPointer = node.mUnionArrayPointer;
+}
+
+TIntermAggregate::TIntermAggregate(const TIntermAggregate &node)
+ : TIntermOperator(node),
+ mName(node.mName),
+ mUserDefined(node.mUserDefined),
+ mFunctionId(node.mFunctionId),
+ mUseEmulatedFunction(node.mUseEmulatedFunction),
+ mGotPrecisionFromChildren(node.mGotPrecisionFromChildren)
+{
+ for (TIntermNode *child : node.mSequence)
+ {
+ TIntermTyped *typedChild = child->getAsTyped();
+ ASSERT(typedChild != nullptr);
+ TIntermTyped *childCopy = typedChild->deepCopy();
+ mSequence.push_back(childCopy);
+ }
+}
+
+TIntermBinary::TIntermBinary(const TIntermBinary &node)
+ : TIntermOperator(node), mAddIndexClamp(node.mAddIndexClamp)
+{
+ TIntermTyped *leftCopy = node.mLeft->deepCopy();
+ TIntermTyped *rightCopy = node.mRight->deepCopy();
+ ASSERT(leftCopy != nullptr && rightCopy != nullptr);
+ mLeft = leftCopy;
+ mRight = rightCopy;
+}
+
+TIntermUnary::TIntermUnary(const TIntermUnary &node)
+ : TIntermOperator(node), mUseEmulatedFunction(node.mUseEmulatedFunction)
+{
+ TIntermTyped *operandCopy = node.mOperand->deepCopy();
+ ASSERT(operandCopy != nullptr);
+ mOperand = operandCopy;
+}
+
+TIntermSelection::TIntermSelection(const TIntermSelection &node) : TIntermTyped(node)
+{
+ // Only supported for ternary nodes, not if statements.
+ TIntermTyped *trueTyped = node.mTrueBlock->getAsTyped();
+ TIntermTyped *falseTyped = node.mFalseBlock->getAsTyped();
+ ASSERT(trueTyped != nullptr);
+ ASSERT(falseTyped != nullptr);
+ TIntermTyped *conditionCopy = node.mCondition->deepCopy();
+ TIntermTyped *trueCopy = trueTyped->deepCopy();
+ TIntermTyped *falseCopy = falseTyped->deepCopy();
+ ASSERT(conditionCopy != nullptr && trueCopy != nullptr && falseCopy != nullptr);
+ mCondition = conditionCopy;
+ mTrueBlock = trueCopy;
+ mFalseBlock = falseCopy;
+}
+
//
// Say whether or not an operation node changes the value of a variable.
//
@@ -291,6 +439,22 @@ bool TIntermOperator::isAssignment() const
}
}
+bool TIntermOperator::isMultiplication() const
+{
+ switch (mOp)
+ {
+ case EOpMul:
+ case EOpMatrixTimesMatrix:
+ case EOpMatrixTimesVector:
+ case EOpMatrixTimesScalar:
+ case EOpVectorTimesMatrix:
+ case EOpVectorTimesScalar:
+ return true;
+ default:
+ return false;
+ }
+}
+
//
// returns true if the operator is for one of the constructors
//
@@ -302,7 +466,13 @@ bool TIntermOperator::isConstructor() const
case EOpConstructVec3:
case EOpConstructVec4:
case EOpConstructMat2:
+ case EOpConstructMat2x3:
+ case EOpConstructMat2x4:
+ case EOpConstructMat3x2:
case EOpConstructMat3:
+ case EOpConstructMat3x4:
+ case EOpConstructMat4x2:
+ case EOpConstructMat4x3:
case EOpConstructMat4:
case EOpConstructFloat:
case EOpConstructIVec2:
@@ -364,7 +534,10 @@ void TIntermUnary::promote(const TType *funcReturnType)
}
}
- mType.setQualifier(EvqTemporary);
+ if (mOperand->getQualifier() == EvqConst)
+ mType.setQualifier(EvqConst);
+ else
+ mType.setQualifier(EvqTemporary);
}
//
@@ -389,10 +562,12 @@ bool TIntermBinary::promote(TInfoSink &infoSink)
mLeft->getPrecision(), mRight->getPrecision());
getTypePointer()->setPrecision(higherPrecision);
+ TQualifier resultQualifier = EvqConst;
// Binary operations results in temporary variables unless both
// operands are const.
if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
{
+ resultQualifier = EvqTemporary;
getTypePointer()->setQualifier(EvqTemporary);
}
@@ -447,14 +622,15 @@ bool TIntermBinary::promote(TInfoSink &infoSink)
if (mLeft->isVector())
{
mOp = EOpVectorTimesMatrix;
- setType(TType(basicType, higherPrecision, EvqTemporary,
- mRight->getCols(), 1));
+ setType(TType(basicType, higherPrecision, resultQualifier,
+ static_cast<unsigned char>(mRight->getCols()), 1));
}
else
{
mOp = EOpMatrixTimesScalar;
- setType(TType(basicType, higherPrecision, EvqTemporary,
- mRight->getCols(), mRight->getRows()));
+ setType(TType(basicType, higherPrecision, resultQualifier,
+ static_cast<unsigned char>(mRight->getCols()),
+ static_cast<unsigned char>(mRight->getRows())));
}
}
else if (mLeft->isMatrix() && !mRight->isMatrix())
@@ -462,8 +638,8 @@ bool TIntermBinary::promote(TInfoSink &infoSink)
if (mRight->isVector())
{
mOp = EOpMatrixTimesVector;
- setType(TType(basicType, higherPrecision, EvqTemporary,
- mLeft->getRows(), 1));
+ setType(TType(basicType, higherPrecision, resultQualifier,
+ static_cast<unsigned char>(mLeft->getRows()), 1));
}
else
{
@@ -473,8 +649,9 @@ bool TIntermBinary::promote(TInfoSink &infoSink)
else if (mLeft->isMatrix() && mRight->isMatrix())
{
mOp = EOpMatrixTimesMatrix;
- setType(TType(basicType, higherPrecision, EvqTemporary,
- mRight->getCols(), mLeft->getRows()));
+ setType(TType(basicType, higherPrecision, resultQualifier,
+ static_cast<unsigned char>(mRight->getCols()),
+ static_cast<unsigned char>(mLeft->getRows())));
}
else if (!mLeft->isMatrix() && !mRight->isMatrix())
{
@@ -485,8 +662,8 @@ bool TIntermBinary::promote(TInfoSink &infoSink)
else if (mLeft->isVector() || mRight->isVector())
{
mOp = EOpVectorTimesScalar;
- setType(TType(basicType, higherPrecision, EvqTemporary,
- nominalSize, 1));
+ setType(TType(basicType, higherPrecision, resultQualifier,
+ static_cast<unsigned char>(nominalSize), 1));
}
}
else
@@ -528,8 +705,9 @@ bool TIntermBinary::promote(TInfoSink &infoSink)
else if (mLeft->isMatrix() && mRight->isMatrix())
{
mOp = EOpMatrixTimesMatrixAssign;
- setType(TType(basicType, higherPrecision, EvqTemporary,
- mRight->getCols(), mLeft->getRows()));
+ setType(TType(basicType, higherPrecision, resultQualifier,
+ static_cast<unsigned char>(mRight->getCols()),
+ static_cast<unsigned char>(mLeft->getRows())));
}
else if (!mLeft->isMatrix() && !mRight->isMatrix())
{
@@ -542,8 +720,8 @@ bool TIntermBinary::promote(TInfoSink &infoSink)
if (!mLeft->isVector())
return false;
mOp = EOpVectorTimesScalarAssign;
- setType(TType(basicType, higherPrecision, EvqTemporary,
- mLeft->getNominalSize(), 1));
+ setType(TType(basicType, higherPrecision, resultQualifier,
+ static_cast<unsigned char>(mLeft->getNominalSize()), 1));
}
}
else
@@ -612,8 +790,9 @@ bool TIntermBinary::promote(TInfoSink &infoSink)
{
const int secondarySize = std::max(
mLeft->getSecondarySize(), mRight->getSecondarySize());
- setType(TType(basicType, higherPrecision, EvqTemporary,
- nominalSize, secondarySize));
+ setType(TType(basicType, higherPrecision, resultQualifier,
+ static_cast<unsigned char>(nominalSize),
+ static_cast<unsigned char>(secondarySize)));
if (mLeft->isArray())
{
ASSERT(mLeft->getArraySize() == mRight->getArraySize());
@@ -639,560 +818,1778 @@ bool TIntermBinary::promote(TInfoSink &infoSink)
return true;
}
+TIntermTyped *TIntermBinary::fold(TInfoSink &infoSink)
+{
+ TIntermConstantUnion *leftConstant = mLeft->getAsConstantUnion();
+ TIntermConstantUnion *rightConstant = mRight->getAsConstantUnion();
+ if (leftConstant == nullptr || rightConstant == nullptr)
+ {
+ return nullptr;
+ }
+ TConstantUnion *constArray = leftConstant->foldBinary(mOp, rightConstant, infoSink);
+
+ // Nodes may be constant folded without being qualified as constant.
+ TQualifier resultQualifier = EvqConst;
+ if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
+ {
+ resultQualifier = EvqTemporary;
+ }
+ return CreateFoldedNode(constArray, this, resultQualifier);
+}
+
+TIntermTyped *TIntermUnary::fold(TInfoSink &infoSink)
+{
+ TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
+ if (operandConstant == nullptr)
+ {
+ return nullptr;
+ }
+
+ TConstantUnion *constArray = nullptr;
+ switch (mOp)
+ {
+ case EOpAny:
+ case EOpAll:
+ case EOpLength:
+ case EOpTranspose:
+ case EOpDeterminant:
+ case EOpInverse:
+ case EOpPackSnorm2x16:
+ case EOpUnpackSnorm2x16:
+ case EOpPackUnorm2x16:
+ case EOpUnpackUnorm2x16:
+ case EOpPackHalf2x16:
+ case EOpUnpackHalf2x16:
+ constArray = operandConstant->foldUnaryWithDifferentReturnType(mOp, infoSink);
+ break;
+ default:
+ constArray = operandConstant->foldUnaryWithSameReturnType(mOp, infoSink);
+ break;
+ }
+
+ // Nodes may be constant folded without being qualified as constant.
+ TQualifier resultQualifier = mOperand->getQualifier() == EvqConst ? EvqConst : EvqTemporary;
+ return CreateFoldedNode(constArray, this, resultQualifier);
+}
+
+TIntermTyped *TIntermAggregate::fold(TInfoSink &infoSink)
+{
+ // Make sure that all params are constant before actual constant folding.
+ for (auto *param : *getSequence())
+ {
+ if (param->getAsConstantUnion() == nullptr)
+ {
+ return nullptr;
+ }
+ }
+ TConstantUnion *constArray = nullptr;
+ if (isConstructor())
+ constArray = TIntermConstantUnion::FoldAggregateConstructor(this, infoSink);
+ else
+ constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, infoSink);
+
+ // Nodes may be constant folded without being qualified as constant.
+ TQualifier resultQualifier = areChildrenConstQualified() ? EvqConst : EvqTemporary;
+ return CreateFoldedNode(constArray, this, resultQualifier);
+}
+
//
// The fold functions see if an operation on a constant can be done in place,
// without generating run-time code.
//
-// Returns the node to keep using, which may or may not be the node passed in.
+// Returns the constant value to keep using or nullptr.
//
-TIntermTyped *TIntermConstantUnion::fold(
- TOperator op, TIntermTyped *constantNode, TInfoSink &infoSink)
+TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op, TIntermConstantUnion *rightNode, TInfoSink &infoSink)
{
- ConstantUnion *unionArray = getUnionArrayPointer();
+ const TConstantUnion *leftArray = getUnionArrayPointer();
+ const TConstantUnion *rightArray = rightNode->getUnionArrayPointer();
- if (!unionArray)
- return NULL;
+ if (!leftArray)
+ return nullptr;
+ if (!rightArray)
+ return nullptr;
size_t objectSize = getType().getObjectSize();
- if (constantNode)
+ // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
+ if (rightNode->getType().getObjectSize() == 1 && objectSize > 1)
+ {
+ rightArray = Vectorize(*rightNode->getUnionArrayPointer(), objectSize);
+ }
+ else if (rightNode->getType().getObjectSize() > 1 && objectSize == 1)
{
- // binary operations
- TIntermConstantUnion *node = constantNode->getAsConstantUnion();
- ConstantUnion *rightUnionArray = node->getUnionArrayPointer();
- TType returnType = getType();
+ // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
+ leftArray = Vectorize(*getUnionArrayPointer(), rightNode->getType().getObjectSize());
+ objectSize = rightNode->getType().getObjectSize();
+ }
- if (!rightUnionArray)
- return NULL;
+ TConstantUnion *resultArray = nullptr;
- // for a case like float f = 1.2 + vec4(2,3,4,5);
- if (constantNode->getType().getObjectSize() == 1 && objectSize > 1)
- {
- rightUnionArray = new ConstantUnion[objectSize];
- for (size_t i = 0; i < objectSize; ++i)
- {
- rightUnionArray[i] = *node->getUnionArrayPointer();
- }
- returnType = getType();
- }
- else if (constantNode->getType().getObjectSize() > 1 && objectSize == 1)
- {
- // for a case like float f = vec4(2,3,4,5) + 1.2;
- unionArray = new ConstantUnion[constantNode->getType().getObjectSize()];
- for (size_t i = 0; i < constantNode->getType().getObjectSize(); ++i)
- {
- unionArray[i] = *getUnionArrayPointer();
- }
- returnType = node->getType();
- objectSize = constantNode->getType().getObjectSize();
- }
+ switch(op)
+ {
+ case EOpAdd:
+ resultArray = new TConstantUnion[objectSize];
+ for (size_t i = 0; i < objectSize; i++)
+ resultArray[i] = leftArray[i] + rightArray[i];
+ break;
+ case EOpSub:
+ resultArray = new TConstantUnion[objectSize];
+ for (size_t i = 0; i < objectSize; i++)
+ resultArray[i] = leftArray[i] - rightArray[i];
+ break;
- ConstantUnion *tempConstArray = NULL;
- TIntermConstantUnion *tempNode;
+ case EOpMul:
+ case EOpVectorTimesScalar:
+ case EOpMatrixTimesScalar:
+ resultArray = new TConstantUnion[objectSize];
+ for (size_t i = 0; i < objectSize; i++)
+ resultArray[i] = leftArray[i] * rightArray[i];
+ break;
- bool boolNodeFlag = false;
- switch(op)
+ case EOpMatrixTimesMatrix:
{
- case EOpAdd:
- tempConstArray = new ConstantUnion[objectSize];
- for (size_t i = 0; i < objectSize; i++)
- tempConstArray[i] = unionArray[i] + rightUnionArray[i];
- break;
- case EOpSub:
- tempConstArray = new ConstantUnion[objectSize];
- for (size_t i = 0; i < objectSize; i++)
- tempConstArray[i] = unionArray[i] - rightUnionArray[i];
- break;
-
- case EOpMul:
- case EOpVectorTimesScalar:
- case EOpMatrixTimesScalar:
- tempConstArray = new ConstantUnion[objectSize];
- for (size_t i = 0; i < objectSize; i++)
- tempConstArray[i] = unionArray[i] * rightUnionArray[i];
- break;
-
- case EOpMatrixTimesMatrix:
+ if (getType().getBasicType() != EbtFloat ||
+ rightNode->getBasicType() != EbtFloat)
{
- if (getType().getBasicType() != EbtFloat ||
- node->getBasicType() != EbtFloat)
- {
- infoSink.info.message(
- EPrefixInternalError, getLine(),
- "Constant Folding cannot be done for matrix multiply");
- return NULL;
- }
+ infoSink.info.message(
+ EPrefixInternalError, getLine(),
+ "Constant Folding cannot be done for matrix multiply");
+ return nullptr;
+ }
- const int leftCols = getCols();
- const int leftRows = getRows();
- const int rightCols = constantNode->getType().getCols();
- const int rightRows = constantNode->getType().getRows();
- const int resultCols = rightCols;
- const int resultRows = leftRows;
+ const int leftCols = getCols();
+ const int leftRows = getRows();
+ const int rightCols = rightNode->getType().getCols();
+ const int rightRows = rightNode->getType().getRows();
+ const int resultCols = rightCols;
+ const int resultRows = leftRows;
- tempConstArray = new ConstantUnion[resultCols*resultRows];
- for (int row = 0; row < resultRows; row++)
+ resultArray = new TConstantUnion[resultCols * resultRows];
+ for (int row = 0; row < resultRows; row++)
+ {
+ for (int column = 0; column < resultCols; column++)
{
- for (int column = 0; column < resultCols; column++)
+ resultArray[resultRows * column + row].setFConst(0.0f);
+ for (int i = 0; i < leftCols; i++)
{
- tempConstArray[resultRows * column + row].setFConst(0.0f);
- for (int i = 0; i < leftCols; i++)
- {
- tempConstArray[resultRows * column + row].setFConst(
- tempConstArray[resultRows * column + row].getFConst() +
- unionArray[i * leftRows + row].getFConst() *
- rightUnionArray[column * rightRows + i].getFConst());
- }
+ resultArray[resultRows * column + row].setFConst(
+ resultArray[resultRows * column + row].getFConst() +
+ leftArray[i * leftRows + row].getFConst() *
+ rightArray[column * rightRows + i].getFConst());
}
}
-
- // update return type for matrix product
- returnType.setPrimarySize(resultCols);
- returnType.setSecondarySize(resultRows);
}
- break;
+ }
+ break;
- case EOpDiv:
- case EOpIMod:
+ case EOpDiv:
+ case EOpIMod:
+ {
+ resultArray = new TConstantUnion[objectSize];
+ for (size_t i = 0; i < objectSize; i++)
{
- tempConstArray = new ConstantUnion[objectSize];
- for (size_t i = 0; i < objectSize; i++)
+ switch (getType().getBasicType())
{
- switch (getType().getBasicType())
+ case EbtFloat:
+ if (rightArray[i] == 0.0f)
{
- case EbtFloat:
- if (rightUnionArray[i] == 0.0f)
- {
- infoSink.info.message(
- EPrefixWarning, getLine(),
- "Divide by zero error during constant folding");
- tempConstArray[i].setFConst(
- unionArray[i].getFConst() < 0 ? -FLT_MAX : FLT_MAX);
- }
- else
- {
- ASSERT(op == EOpDiv);
- tempConstArray[i].setFConst(
- unionArray[i].getFConst() /
- rightUnionArray[i].getFConst());
- }
- break;
+ infoSink.info.message(EPrefixWarning, getLine(),
+ "Divide by zero error during constant folding");
+ resultArray[i].setFConst(leftArray[i].getFConst() < 0 ? -FLT_MAX : FLT_MAX);
+ }
+ else
+ {
+ ASSERT(op == EOpDiv);
+ resultArray[i].setFConst(leftArray[i].getFConst() / rightArray[i].getFConst());
+ }
+ break;
- case EbtInt:
- if (rightUnionArray[i] == 0)
+ case EbtInt:
+ if (rightArray[i] == 0)
+ {
+ infoSink.info.message(EPrefixWarning, getLine(),
+ "Divide by zero error during constant folding");
+ resultArray[i].setIConst(INT_MAX);
+ }
+ else
+ {
+ if (op == EOpDiv)
{
- infoSink.info.message(
- EPrefixWarning, getLine(),
- "Divide by zero error during constant folding");
- tempConstArray[i].setIConst(INT_MAX);
+ resultArray[i].setIConst(leftArray[i].getIConst() / rightArray[i].getIConst());
}
else
{
- 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());
- }
+ ASSERT(op == EOpIMod);
+ resultArray[i].setIConst(leftArray[i].getIConst() % rightArray[i].getIConst());
}
- break;
+ }
+ break;
- case EbtUInt:
- if (rightUnionArray[i] == 0)
+ case EbtUInt:
+ if (rightArray[i] == 0)
+ {
+ infoSink.info.message(EPrefixWarning, getLine(),
+ "Divide by zero error during constant folding");
+ resultArray[i].setUConst(UINT_MAX);
+ }
+ else
+ {
+ if (op == EOpDiv)
{
- infoSink.info.message(
- EPrefixWarning, getLine(),
- "Divide by zero error during constant folding");
- tempConstArray[i].setUConst(UINT_MAX);
+ resultArray[i].setUConst(leftArray[i].getUConst() / rightArray[i].getUConst());
}
else
{
- 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());
- }
+ ASSERT(op == EOpIMod);
+ resultArray[i].setUConst(leftArray[i].getUConst() % rightArray[i].getUConst());
}
- break;
-
- default:
- infoSink.info.message(
- EPrefixInternalError, getLine(),
- "Constant folding cannot be done for \"/\"");
- return NULL;
}
+ break;
+
+ default:
+ infoSink.info.message(EPrefixInternalError, getLine(),
+ "Constant folding cannot be done for \"/\"");
+ return nullptr;
}
}
- break;
+ }
+ break;
+
+ case EOpMatrixTimesVector:
+ {
+ if (rightNode->getBasicType() != EbtFloat)
+ {
+ infoSink.info.message(EPrefixInternalError, getLine(),
+ "Constant Folding cannot be done for matrix times vector");
+ return nullptr;
+ }
- case EOpMatrixTimesVector:
+ const int matrixCols = getCols();
+ const int matrixRows = getRows();
+
+ resultArray = new TConstantUnion[matrixRows];
+
+ for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
{
- if (node->getBasicType() != EbtFloat)
+ resultArray[matrixRow].setFConst(0.0f);
+ for (int col = 0; col < matrixCols; col++)
{
- infoSink.info.message(
- EPrefixInternalError, getLine(),
- "Constant Folding cannot be done for matrix times vector");
- return NULL;
+ resultArray[matrixRow].setFConst(resultArray[matrixRow].getFConst() +
+ leftArray[col * matrixRows + matrixRow].getFConst() *
+ rightArray[col].getFConst());
}
+ }
+ }
+ break;
+
+ case EOpVectorTimesMatrix:
+ {
+ if (getType().getBasicType() != EbtFloat)
+ {
+ infoSink.info.message(EPrefixInternalError, getLine(),
+ "Constant Folding cannot be done for vector times matrix");
+ return nullptr;
+ }
- const int matrixCols = getCols();
- const int matrixRows = getRows();
+ const int matrixCols = rightNode->getType().getCols();
+ const int matrixRows = rightNode->getType().getRows();
- tempConstArray = new ConstantUnion[matrixRows];
+ resultArray = new TConstantUnion[matrixCols];
+ for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
+ {
+ resultArray[matrixCol].setFConst(0.0f);
for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
{
- tempConstArray[matrixRow].setFConst(0.0f);
- for (int col = 0; col < matrixCols; col++)
- {
- tempConstArray[matrixRow].setFConst(
- tempConstArray[matrixRow].getFConst() +
- unionArray[col * matrixRows + matrixRow].getFConst() *
- rightUnionArray[col].getFConst());
- }
+ resultArray[matrixCol].setFConst(resultArray[matrixCol].getFConst() +
+ leftArray[matrixRow].getFConst() *
+ rightArray[matrixCol * matrixRows + matrixRow].getFConst());
}
+ }
+ }
+ break;
- returnType = node->getType();
- returnType.setPrimarySize(matrixRows);
-
- tempNode = new TIntermConstantUnion(tempConstArray, returnType);
- tempNode->setLine(getLine());
+ case EOpLogicalAnd:
+ {
+ resultArray = new TConstantUnion[objectSize];
+ for (size_t i = 0; i < objectSize; i++)
+ {
+ resultArray[i] = leftArray[i] && rightArray[i];
+ }
+ }
+ break;
- return tempNode;
+ case EOpLogicalOr:
+ {
+ resultArray = new TConstantUnion[objectSize];
+ for (size_t i = 0; i < objectSize; i++)
+ {
+ resultArray[i] = leftArray[i] || rightArray[i];
}
+ }
+ break;
- case EOpVectorTimesMatrix:
+ case EOpLogicalXor:
+ {
+ resultArray = new TConstantUnion[objectSize];
+ for (size_t i = 0; i < objectSize; i++)
{
- if (getType().getBasicType() != EbtFloat)
+ switch (getType().getBasicType())
{
- infoSink.info.message(
- EPrefixInternalError, getLine(),
- "Constant Folding cannot be done for vector times matrix");
- return NULL;
+ case EbtBool:
+ resultArray[i].setBConst(leftArray[i] != rightArray[i]);
+ break;
+ default:
+ UNREACHABLE();
+ break;
}
+ }
+ }
+ break;
- const int matrixCols = constantNode->getType().getCols();
- const int matrixRows = constantNode->getType().getRows();
+ case EOpBitwiseAnd:
+ resultArray = new TConstantUnion[objectSize];
+ for (size_t i = 0; i < objectSize; i++)
+ resultArray[i] = leftArray[i] & rightArray[i];
+ break;
+ case EOpBitwiseXor:
+ resultArray = new TConstantUnion[objectSize];
+ for (size_t i = 0; i < objectSize; i++)
+ resultArray[i] = leftArray[i] ^ rightArray[i];
+ break;
+ case EOpBitwiseOr:
+ resultArray = new TConstantUnion[objectSize];
+ for (size_t i = 0; i < objectSize; i++)
+ resultArray[i] = leftArray[i] | rightArray[i];
+ break;
+ case EOpBitShiftLeft:
+ resultArray = new TConstantUnion[objectSize];
+ for (size_t i = 0; i < objectSize; i++)
+ resultArray[i] = leftArray[i] << rightArray[i];
+ break;
+ case EOpBitShiftRight:
+ resultArray = new TConstantUnion[objectSize];
+ for (size_t i = 0; i < objectSize; i++)
+ resultArray[i] = leftArray[i] >> rightArray[i];
+ break;
+
+ case EOpLessThan:
+ ASSERT(objectSize == 1);
+ resultArray = new TConstantUnion[1];
+ resultArray->setBConst(*leftArray < *rightArray);
+ break;
- tempConstArray = new ConstantUnion[matrixCols];
+ case EOpGreaterThan:
+ ASSERT(objectSize == 1);
+ resultArray = new TConstantUnion[1];
+ resultArray->setBConst(*leftArray > *rightArray);
+ break;
- for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
+ case EOpLessThanEqual:
+ ASSERT(objectSize == 1);
+ resultArray = new TConstantUnion[1];
+ resultArray->setBConst(!(*leftArray > *rightArray));
+ break;
+
+ case EOpGreaterThanEqual:
+ ASSERT(objectSize == 1);
+ resultArray = new TConstantUnion[1];
+ resultArray->setBConst(!(*leftArray < *rightArray));
+ break;
+
+ case EOpEqual:
+ case EOpNotEqual:
+ {
+ resultArray = new TConstantUnion[1];
+ bool equal = true;
+ for (size_t i = 0; i < objectSize; i++)
+ {
+ if (leftArray[i] != rightArray[i])
{
- tempConstArray[matrixCol].setFConst(0.0f);
- for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
- {
- tempConstArray[matrixCol].setFConst(
- tempConstArray[matrixCol].getFConst() +
- unionArray[matrixRow].getFConst() *
- rightUnionArray[matrixCol * matrixRows + matrixRow].getFConst());
- }
+ equal = false;
+ break; // break out of for loop
}
+ }
+ if (op == EOpEqual)
+ {
+ resultArray->setBConst(equal);
+ }
+ else
+ {
+ resultArray->setBConst(!equal);
+ }
+ }
+ break;
+
+ default:
+ infoSink.info.message(
+ EPrefixInternalError, getLine(),
+ "Invalid operator for constant folding");
+ return nullptr;
+ }
+ return resultArray;
+}
+
+//
+// The fold functions see if an operation on a constant can be done in place,
+// without generating run-time code.
+//
+// Returns the constant value to keep using or nullptr.
+//
+TConstantUnion *TIntermConstantUnion::foldUnaryWithDifferentReturnType(TOperator op, TInfoSink &infoSink)
+{
+ //
+ // Do operations where the return type has a different number of components compared to the operand type.
+ //
+
+ const TConstantUnion *operandArray = getUnionArrayPointer();
+ if (!operandArray)
+ return nullptr;
- returnType.setPrimarySize(matrixCols);
+ size_t objectSize = getType().getObjectSize();
+ TConstantUnion *resultArray = nullptr;
+ switch (op)
+ {
+ case EOpAny:
+ if (getType().getBasicType() == EbtBool)
+ {
+ resultArray = new TConstantUnion();
+ resultArray->setBConst(false);
+ for (size_t i = 0; i < objectSize; i++)
+ {
+ if (operandArray[i].getBConst())
+ {
+ resultArray->setBConst(true);
+ break;
+ }
}
break;
+ }
+ else
+ {
+ infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
+ return nullptr;
+ }
- case EOpLogicalAnd:
- // this code is written for possible future use,
- // will not get executed currently
+ case EOpAll:
+ if (getType().getBasicType() == EbtBool)
+ {
+ resultArray = new TConstantUnion();
+ resultArray->setBConst(true);
+ for (size_t i = 0; i < objectSize; i++)
{
- tempConstArray = new ConstantUnion[objectSize];
- for (size_t i = 0; i < objectSize; i++)
+ if (!operandArray[i].getBConst())
{
- tempConstArray[i] = unionArray[i] && rightUnionArray[i];
+ resultArray->setBConst(false);
+ break;
}
}
break;
+ }
+ else
+ {
+ infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
+ return nullptr;
+ }
- case EOpLogicalOr:
+ case EOpLength:
+ if (getType().getBasicType() == EbtFloat)
+ {
+ resultArray = new TConstantUnion();
+ resultArray->setFConst(VectorLength(operandArray, objectSize));
+ break;
+ }
+ else
+ {
+ infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
+ return nullptr;
+ }
+
+ case EOpTranspose:
+ if (getType().getBasicType() == EbtFloat)
+ {
+ resultArray = new TConstantUnion[objectSize];
+ angle::Matrix<float> result =
+ GetMatrix(operandArray, getType().getNominalSize(), getType().getSecondarySize()).transpose();
+ SetUnionArrayFromMatrix(result, resultArray);
+ break;
+ }
+ else
+ {
+ infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
+ return nullptr;
+ }
+
+ case EOpDeterminant:
+ if (getType().getBasicType() == EbtFloat)
+ {
+ unsigned int size = getType().getNominalSize();
+ ASSERT(size >= 2 && size <= 4);
+ resultArray = new TConstantUnion();
+ resultArray->setFConst(GetMatrix(operandArray, size).determinant());
+ break;
+ }
+ else
+ {
+ infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
+ return nullptr;
+ }
+
+ case EOpInverse:
+ if (getType().getBasicType() == EbtFloat)
+ {
+ unsigned int size = getType().getNominalSize();
+ ASSERT(size >= 2 && size <= 4);
+ resultArray = new TConstantUnion[objectSize];
+ angle::Matrix<float> result = GetMatrix(operandArray, size).inverse();
+ SetUnionArrayFromMatrix(result, resultArray);
+ break;
+ }
+ else
+ {
+ infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
+ return nullptr;
+ }
+
+ case EOpPackSnorm2x16:
+ if (getType().getBasicType() == EbtFloat)
+ {
+ ASSERT(getType().getNominalSize() == 2);
+ resultArray = new TConstantUnion();
+ resultArray->setUConst(gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
+ break;
+ }
+ else
+ {
+ infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
+ return nullptr;
+ }
+
+ case EOpUnpackSnorm2x16:
+ if (getType().getBasicType() == EbtUInt)
+ {
+ resultArray = new TConstantUnion[2];
+ float f1, f2;
+ gl::unpackSnorm2x16(operandArray[0].getUConst(), &f1, &f2);
+ resultArray[0].setFConst(f1);
+ resultArray[1].setFConst(f2);
+ break;
+ }
+ else
+ {
+ infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
+ return nullptr;
+ }
+
+ case EOpPackUnorm2x16:
+ if (getType().getBasicType() == EbtFloat)
+ {
+ ASSERT(getType().getNominalSize() == 2);
+ resultArray = new TConstantUnion();
+ resultArray->setUConst(gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
+ break;
+ }
+ else
+ {
+ infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
+ return nullptr;
+ }
+
+ case EOpUnpackUnorm2x16:
+ if (getType().getBasicType() == EbtUInt)
+ {
+ resultArray = new TConstantUnion[2];
+ float f1, f2;
+ gl::unpackUnorm2x16(operandArray[0].getUConst(), &f1, &f2);
+ resultArray[0].setFConst(f1);
+ resultArray[1].setFConst(f2);
+ break;
+ }
+ else
+ {
+ infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
+ return nullptr;
+ }
+
+ case EOpPackHalf2x16:
+ if (getType().getBasicType() == EbtFloat)
+ {
+ ASSERT(getType().getNominalSize() == 2);
+ resultArray = new TConstantUnion();
+ resultArray->setUConst(gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
+ break;
+ }
+ else
+ {
+ infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
+ return nullptr;
+ }
+
+ case EOpUnpackHalf2x16:
+ if (getType().getBasicType() == EbtUInt)
+ {
+ resultArray = new TConstantUnion[2];
+ float f1, f2;
+ gl::unpackHalf2x16(operandArray[0].getUConst(), &f1, &f2);
+ resultArray[0].setFConst(f1);
+ resultArray[1].setFConst(f2);
+ break;
+ }
+ else
+ {
+ infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
+ return nullptr;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return resultArray;
+}
+
+TConstantUnion *TIntermConstantUnion::foldUnaryWithSameReturnType(TOperator op, TInfoSink &infoSink)
+{
+ //
+ // Do unary operations where the return type is the same as operand type.
+ //
+
+ const TConstantUnion *operandArray = getUnionArrayPointer();
+ if (!operandArray)
+ return nullptr;
+
+ size_t objectSize = getType().getObjectSize();
+
+ TConstantUnion *resultArray = new TConstantUnion[objectSize];
+ for (size_t i = 0; i < objectSize; i++)
+ {
+ switch(op)
+ {
+ case EOpNegative:
+ switch (getType().getBasicType())
+ {
+ case EbtFloat:
+ resultArray[i].setFConst(-operandArray[i].getFConst());
+ break;
+ case EbtInt:
+ resultArray[i].setIConst(-operandArray[i].getIConst());
+ break;
+ case EbtUInt:
+ resultArray[i].setUConst(static_cast<unsigned int>(
+ -static_cast<int>(operandArray[i].getUConst())));
+ break;
+ default:
+ infoSink.info.message(
+ EPrefixInternalError, getLine(),
+ "Unary operation not folded into constant");
+ return nullptr;
+ }
+ break;
+
+ case EOpPositive:
+ switch (getType().getBasicType())
+ {
+ case EbtFloat:
+ resultArray[i].setFConst(operandArray[i].getFConst());
+ break;
+ case EbtInt:
+ resultArray[i].setIConst(operandArray[i].getIConst());
+ break;
+ case EbtUInt:
+ resultArray[i].setUConst(static_cast<unsigned int>(
+ static_cast<int>(operandArray[i].getUConst())));
+ break;
+ default:
+ infoSink.info.message(
+ EPrefixInternalError, getLine(),
+ "Unary operation not folded into constant");
+ return nullptr;
+ }
+ break;
+
+ case EOpLogicalNot:
// this code is written for possible future use,
// will not get executed currently
+ switch (getType().getBasicType())
{
- tempConstArray = new ConstantUnion[objectSize];
- for (size_t i = 0; i < objectSize; i++)
- {
- tempConstArray[i] = unionArray[i] || rightUnionArray[i];
- }
+ case EbtBool:
+ resultArray[i].setBConst(!operandArray[i].getBConst());
+ break;
+ default:
+ infoSink.info.message(
+ EPrefixInternalError, getLine(),
+ "Unary operation not folded into constant");
+ return nullptr;
}
break;
- case EOpLogicalXor:
+ case EOpBitwiseNot:
+ switch (getType().getBasicType())
+ {
+ case EbtInt:
+ resultArray[i].setIConst(~operandArray[i].getIConst());
+ break;
+ case EbtUInt:
+ resultArray[i].setUConst(~operandArray[i].getUConst());
+ break;
+ default:
+ infoSink.info.message(
+ EPrefixInternalError, getLine(),
+ "Unary operation not folded into constant");
+ return nullptr;
+ }
+ break;
+
+ case EOpRadians:
+ if (getType().getBasicType() == EbtFloat)
+ {
+ resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst());
+ break;
+ }
+ infoSink.info.message(
+ EPrefixInternalError, getLine(),
+ "Unary operation not folded into constant");
+ return nullptr;
+
+ case EOpDegrees:
+ if (getType().getBasicType() == EbtFloat)
{
- tempConstArray = new ConstantUnion[objectSize];
- for (size_t i = 0; i < objectSize; i++)
+ resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst());
+ break;
+ }
+ infoSink.info.message(
+ EPrefixInternalError, getLine(),
+ "Unary operation not folded into constant");
+ return nullptr;
+
+ case EOpSin:
+ if (!foldFloatTypeUnary(operandArray[i], &sinf, infoSink, &resultArray[i]))
+ return nullptr;
+ break;
+
+ case EOpCos:
+ if (!foldFloatTypeUnary(operandArray[i], &cosf, infoSink, &resultArray[i]))
+ return nullptr;
+ break;
+
+ case EOpTan:
+ if (!foldFloatTypeUnary(operandArray[i], &tanf, infoSink, &resultArray[i]))
+ return nullptr;
+ break;
+
+ case EOpAsin:
+ // For asin(x), results are undefined if |x| > 1, we are choosing to set result to 0.
+ if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) > 1.0f)
+ UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
+ else if (!foldFloatTypeUnary(operandArray[i], &asinf, infoSink, &resultArray[i]))
+ return nullptr;
+ break;
+
+ case EOpAcos:
+ // For acos(x), results are undefined if |x| > 1, we are choosing to set result to 0.
+ if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) > 1.0f)
+ UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
+ else if (!foldFloatTypeUnary(operandArray[i], &acosf, infoSink, &resultArray[i]))
+ return nullptr;
+ break;
+
+ case EOpAtan:
+ if (!foldFloatTypeUnary(operandArray[i], &atanf, infoSink, &resultArray[i]))
+ return nullptr;
+ break;
+
+ case EOpSinh:
+ if (!foldFloatTypeUnary(operandArray[i], &sinhf, infoSink, &resultArray[i]))
+ return nullptr;
+ break;
+
+ case EOpCosh:
+ if (!foldFloatTypeUnary(operandArray[i], &coshf, infoSink, &resultArray[i]))
+ return nullptr;
+ break;
+
+ case EOpTanh:
+ if (!foldFloatTypeUnary(operandArray[i], &tanhf, infoSink, &resultArray[i]))
+ return nullptr;
+ break;
+
+ case EOpAsinh:
+ if (!foldFloatTypeUnary(operandArray[i], &asinhf, infoSink, &resultArray[i]))
+ return nullptr;
+ break;
+
+ case EOpAcosh:
+ // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
+ if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() < 1.0f)
+ UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
+ else if (!foldFloatTypeUnary(operandArray[i], &acoshf, infoSink, &resultArray[i]))
+ return nullptr;
+ break;
+
+ case EOpAtanh:
+ // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to 0.
+ if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) >= 1.0f)
+ UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
+ else if (!foldFloatTypeUnary(operandArray[i], &atanhf, infoSink, &resultArray[i]))
+ return nullptr;
+ break;
+
+ case EOpAbs:
+ switch (getType().getBasicType())
+ {
+ case EbtFloat:
+ resultArray[i].setFConst(fabsf(operandArray[i].getFConst()));
+ break;
+ case EbtInt:
+ resultArray[i].setIConst(abs(operandArray[i].getIConst()));
+ break;
+ default:
+ infoSink.info.message(
+ EPrefixInternalError, getLine(),
+ "Unary operation not folded into constant");
+ return nullptr;
+ }
+ break;
+
+ case EOpSign:
+ switch (getType().getBasicType())
+ {
+ case EbtFloat:
{
- switch (getType().getBasicType())
- {
- case EbtBool:
- tempConstArray[i].setBConst(
- unionArray[i] == rightUnionArray[i] ? false : true);
- break;
- default:
- UNREACHABLE();
- break;
- }
+ float fConst = operandArray[i].getFConst();
+ float fResult = 0.0f;
+ if (fConst > 0.0f)
+ fResult = 1.0f;
+ else if (fConst < 0.0f)
+ fResult = -1.0f;
+ resultArray[i].setFConst(fResult);
+ }
+ break;
+ case EbtInt:
+ {
+ int iConst = operandArray[i].getIConst();
+ int iResult = 0;
+ if (iConst > 0)
+ iResult = 1;
+ else if (iConst < 0)
+ iResult = -1;
+ resultArray[i].setIConst(iResult);
}
+ break;
+ default:
+ infoSink.info.message(
+ EPrefixInternalError, getLine(),
+ "Unary operation not folded into constant");
+ return nullptr;
}
break;
- case EOpBitwiseAnd:
- tempConstArray = new ConstantUnion[objectSize];
- for (size_t i = 0; i < objectSize; i++)
- tempConstArray[i] = unionArray[i] & rightUnionArray[i];
+ case EOpFloor:
+ if (!foldFloatTypeUnary(operandArray[i], &floorf, infoSink, &resultArray[i]))
+ return nullptr;
break;
- case EOpBitwiseXor:
- tempConstArray = new ConstantUnion[objectSize];
- for (size_t i = 0; i < objectSize; i++)
- tempConstArray[i] = unionArray[i] ^ rightUnionArray[i];
+
+ case EOpTrunc:
+ if (!foldFloatTypeUnary(operandArray[i], &truncf, infoSink, &resultArray[i]))
+ return nullptr;
break;
- case EOpBitwiseOr:
- tempConstArray = new ConstantUnion[objectSize];
- for (size_t i = 0; i < objectSize; i++)
- tempConstArray[i] = unionArray[i] | rightUnionArray[i];
+
+ case EOpRound:
+ if (!foldFloatTypeUnary(operandArray[i], &roundf, infoSink, &resultArray[i]))
+ return nullptr;
break;
- case EOpBitShiftLeft:
- tempConstArray = new ConstantUnion[objectSize];
- for (size_t i = 0; i < objectSize; i++)
- tempConstArray[i] = unionArray[i] << rightUnionArray[i];
+
+ case EOpRoundEven:
+ if (getType().getBasicType() == EbtFloat)
+ {
+ float x = operandArray[i].getFConst();
+ float result;
+ float fractPart = modff(x, &result);
+ if (fabsf(fractPart) == 0.5f)
+ result = 2.0f * roundf(x / 2.0f);
+ else
+ result = roundf(x);
+ resultArray[i].setFConst(result);
+ break;
+ }
+ infoSink.info.message(
+ EPrefixInternalError, getLine(),
+ "Unary operation not folded into constant");
+ return nullptr;
+
+ case EOpCeil:
+ if (!foldFloatTypeUnary(operandArray[i], &ceilf, infoSink, &resultArray[i]))
+ return nullptr;
break;
- case EOpBitShiftRight:
- tempConstArray = new ConstantUnion[objectSize];
- for (size_t i = 0; i < objectSize; i++)
- tempConstArray[i] = unionArray[i] >> rightUnionArray[i];
+
+ case EOpFract:
+ if (getType().getBasicType() == EbtFloat)
+ {
+ float x = operandArray[i].getFConst();
+ resultArray[i].setFConst(x - floorf(x));
+ break;
+ }
+ infoSink.info.message(
+ EPrefixInternalError, getLine(),
+ "Unary operation not folded into constant");
+ return nullptr;
+
+ case EOpIsNan:
+ if (getType().getBasicType() == EbtFloat)
+ {
+ resultArray[i].setBConst(gl::isNaN(operandArray[0].getFConst()));
+ break;
+ }
+ infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
+ return nullptr;
+
+ case EOpIsInf:
+ if (getType().getBasicType() == EbtFloat)
+ {
+ resultArray[i].setBConst(gl::isInf(operandArray[0].getFConst()));
+ break;
+ }
+ infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
+ return nullptr;
+
+ case EOpFloatBitsToInt:
+ if (getType().getBasicType() == EbtFloat)
+ {
+ resultArray[i].setIConst(gl::bitCast<int32_t>(operandArray[0].getFConst()));
+ break;
+ }
+ infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
+ return nullptr;
+
+ case EOpFloatBitsToUint:
+ if (getType().getBasicType() == EbtFloat)
+ {
+ resultArray[i].setUConst(gl::bitCast<uint32_t>(operandArray[0].getFConst()));
+ break;
+ }
+ infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
+ return nullptr;
+
+ case EOpIntBitsToFloat:
+ if (getType().getBasicType() == EbtInt)
+ {
+ resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getIConst()));
+ break;
+ }
+ infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
+ return nullptr;
+
+ case EOpUintBitsToFloat:
+ if (getType().getBasicType() == EbtUInt)
+ {
+ resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getUConst()));
+ break;
+ }
+ infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
+ return nullptr;
+
+ case EOpExp:
+ if (!foldFloatTypeUnary(operandArray[i], &expf, infoSink, &resultArray[i]))
+ return nullptr;
break;
- case EOpLessThan:
- ASSERT(objectSize == 1);
- tempConstArray = new ConstantUnion[1];
- tempConstArray->setBConst(*unionArray < *rightUnionArray);
- returnType = TType(EbtBool, EbpUndefined, EvqConst);
+ case EOpLog:
+ // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
+ if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f)
+ UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
+ else if (!foldFloatTypeUnary(operandArray[i], &logf, infoSink, &resultArray[i]))
+ return nullptr;
break;
- case EOpGreaterThan:
- ASSERT(objectSize == 1);
- tempConstArray = new ConstantUnion[1];
- tempConstArray->setBConst(*unionArray > *rightUnionArray);
- returnType = TType(EbtBool, EbpUndefined, EvqConst);
+ case EOpExp2:
+ if (!foldFloatTypeUnary(operandArray[i], &exp2f, infoSink, &resultArray[i]))
+ return nullptr;
break;
- case EOpLessThanEqual:
+ case EOpLog2:
+ // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
+ // And log2f is not available on some plarforms like old android, so just using log(x)/log(2) here.
+ if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f)
+ UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
+ else if (!foldFloatTypeUnary(operandArray[i], &logf, infoSink, &resultArray[i]))
+ return nullptr;
+ else
+ resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f));
+ break;
+
+ case EOpSqrt:
+ // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
+ if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() < 0.0f)
+ UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
+ else if (!foldFloatTypeUnary(operandArray[i], &sqrtf, infoSink, &resultArray[i]))
+ return nullptr;
+ break;
+
+ case EOpInverseSqrt:
+ // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
+ // so getting the square root first using builtin function sqrt() and then taking its inverse.
+ // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set result to 0.
+ if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f)
+ UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
+ else if (!foldFloatTypeUnary(operandArray[i], &sqrtf, infoSink, &resultArray[i]))
+ return nullptr;
+ else
+ resultArray[i].setFConst(1.0f / resultArray[i].getFConst());
+ break;
+
+ case EOpVectorLogicalNot:
+ if (getType().getBasicType() == EbtBool)
{
- ASSERT(objectSize == 1);
- ConstantUnion constant;
- constant.setBConst(*unionArray > *rightUnionArray);
- tempConstArray = new ConstantUnion[1];
- tempConstArray->setBConst(!constant.getBConst());
- returnType = TType(EbtBool, EbpUndefined, EvqConst);
+ resultArray[i].setBConst(!operandArray[i].getBConst());
break;
}
+ infoSink.info.message(
+ EPrefixInternalError, getLine(),
+ "Unary operation not folded into constant");
+ return nullptr;
- case EOpGreaterThanEqual:
+ case EOpNormalize:
+ if (getType().getBasicType() == EbtFloat)
{
- ASSERT(objectSize == 1);
- ConstantUnion constant;
- constant.setBConst(*unionArray < *rightUnionArray);
- tempConstArray = new ConstantUnion[1];
- tempConstArray->setBConst(!constant.getBConst());
- returnType = TType(EbtBool, EbpUndefined, EvqConst);
+ float x = operandArray[i].getFConst();
+ float length = VectorLength(operandArray, objectSize);
+ if (length)
+ resultArray[i].setFConst(x / length);
+ else
+ UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink,
+ &resultArray[i]);
break;
}
+ infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
+ return nullptr;
- case EOpEqual:
- if (getType().getBasicType() == EbtStruct)
+ case EOpDFdx:
+ case EOpDFdy:
+ case EOpFwidth:
+ if (getType().getBasicType() == EbtFloat)
{
- if (!CompareStructure(node->getType(),
- node->getUnionArrayPointer(),
- unionArray))
+ // Derivatives of constant arguments should be 0.
+ resultArray[i].setFConst(0.0f);
+ break;
+ }
+ infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
+ return nullptr;
+
+ default:
+ return nullptr;
+ }
+ }
+
+ return resultArray;
+}
+
+bool TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter, FloatTypeUnaryFunc builtinFunc,
+ TInfoSink &infoSink, TConstantUnion *result) const
+{
+ ASSERT(builtinFunc);
+
+ if (getType().getBasicType() == EbtFloat)
+ {
+ result->setFConst(builtinFunc(parameter.getFConst()));
+ return true;
+ }
+
+ infoSink.info.message(
+ EPrefixInternalError, getLine(),
+ "Unary operation not folded into constant");
+ return false;
+}
+
+// static
+TConstantUnion *TIntermConstantUnion::FoldAggregateConstructor(TIntermAggregate *aggregate,
+ TInfoSink &infoSink)
+{
+ ASSERT(aggregate->getSequence()->size() > 0u);
+ size_t resultSize = aggregate->getType().getObjectSize();
+ TConstantUnion *resultArray = new TConstantUnion[resultSize];
+ TBasicType basicType = aggregate->getBasicType();
+
+ size_t resultIndex = 0u;
+
+ if (aggregate->getSequence()->size() == 1u)
+ {
+ TIntermNode *argument = aggregate->getSequence()->front();
+ TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
+ const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
+ // Check the special case of constructing a matrix diagonal from a single scalar,
+ // or a vector from a single scalar.
+ if (argumentConstant->getType().getObjectSize() == 1u)
+ {
+ if (aggregate->isMatrix())
+ {
+ int resultCols = aggregate->getType().getCols();
+ int resultRows = aggregate->getType().getRows();
+ for (int col = 0; col < resultCols; ++col)
{
- boolNodeFlag = true;
+ for (int row = 0; row < resultRows; ++row)
+ {
+ if (col == row)
+ {
+ resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
+ }
+ else
+ {
+ resultArray[resultIndex].setFConst(0.0f);
+ }
+ ++resultIndex;
+ }
}
}
else
{
- for (size_t i = 0; i < objectSize; i++)
+ while (resultIndex < resultSize)
{
- if (unionArray[i] != rightUnionArray[i])
+ resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
+ ++resultIndex;
+ }
+ }
+ ASSERT(resultIndex == resultSize);
+ return resultArray;
+ }
+ else if (aggregate->isMatrix() && argumentConstant->isMatrix())
+ {
+ // The special case of constructing a matrix from a matrix.
+ int argumentCols = argumentConstant->getType().getCols();
+ int argumentRows = argumentConstant->getType().getRows();
+ int resultCols = aggregate->getType().getCols();
+ int resultRows = aggregate->getType().getRows();
+ for (int col = 0; col < resultCols; ++col)
+ {
+ for (int row = 0; row < resultRows; ++row)
+ {
+ if (col < argumentCols && row < argumentRows)
+ {
+ resultArray[resultIndex].cast(basicType,
+ argumentUnionArray[col * argumentRows + row]);
+ }
+ else if (col == row)
{
- boolNodeFlag = true;
- break; // break out of for loop
+ resultArray[resultIndex].setFConst(1.0f);
}
+ else
+ {
+ resultArray[resultIndex].setFConst(0.0f);
+ }
+ ++resultIndex;
}
}
+ ASSERT(resultIndex == resultSize);
+ return resultArray;
+ }
+ }
- tempConstArray = new ConstantUnion[1];
- if (!boolNodeFlag)
+ for (TIntermNode *&argument : *aggregate->getSequence())
+ {
+ TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
+ size_t argumentSize = argumentConstant->getType().getObjectSize();
+ const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
+ for (size_t i = 0u; i < argumentSize; ++i)
+ {
+ if (resultIndex >= resultSize)
+ break;
+ resultArray[resultIndex].cast(basicType, argumentUnionArray[i]);
+ ++resultIndex;
+ }
+ }
+ ASSERT(resultIndex == resultSize);
+ return resultArray;
+}
+
+// static
+TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate, TInfoSink &infoSink)
+{
+ TOperator op = aggregate->getOp();
+ TIntermSequence *sequence = aggregate->getSequence();
+ unsigned int paramsCount = static_cast<unsigned int>(sequence->size());
+ std::vector<const TConstantUnion *> unionArrays(paramsCount);
+ std::vector<size_t> objectSizes(paramsCount);
+ size_t maxObjectSize = 0;
+ TBasicType basicType = EbtVoid;
+ TSourceLoc loc;
+ for (unsigned int i = 0; i < paramsCount; i++)
+ {
+ TIntermConstantUnion *paramConstant = (*sequence)[i]->getAsConstantUnion();
+ ASSERT(paramConstant != nullptr); // Should be checked already.
+
+ if (i == 0)
+ {
+ basicType = paramConstant->getType().getBasicType();
+ loc = paramConstant->getLine();
+ }
+ unionArrays[i] = paramConstant->getUnionArrayPointer();
+ objectSizes[i] = paramConstant->getType().getObjectSize();
+ if (objectSizes[i] > maxObjectSize)
+ maxObjectSize = objectSizes[i];
+ }
+
+ if (!(*sequence)[0]->getAsTyped()->isMatrix())
+ {
+ for (unsigned int i = 0; i < paramsCount; i++)
+ if (objectSizes[i] != maxObjectSize)
+ unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
+ }
+
+ TConstantUnion *resultArray = nullptr;
+ if (paramsCount == 2)
+ {
+ //
+ // Binary built-in
+ //
+ switch (op)
+ {
+ case EOpAtan:
{
- tempConstArray->setBConst(true);
+ if (basicType == EbtFloat)
+ {
+ resultArray = new TConstantUnion[maxObjectSize];
+ for (size_t i = 0; i < maxObjectSize; i++)
+ {
+ float y = unionArrays[0][i].getFConst();
+ float x = unionArrays[1][i].getFConst();
+ // Results are undefined if x and y are both 0.
+ if (x == 0.0f && y == 0.0f)
+ UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
+ else
+ resultArray[i].setFConst(atan2f(y, x));
+ }
+ }
+ else
+ UNREACHABLE();
}
- else
+ break;
+
+ case EOpPow:
{
- tempConstArray->setBConst(false);
+ if (basicType == EbtFloat)
+ {
+ resultArray = new TConstantUnion[maxObjectSize];
+ for (size_t i = 0; i < maxObjectSize; i++)
+ {
+ float x = unionArrays[0][i].getFConst();
+ float y = unionArrays[1][i].getFConst();
+ // Results are undefined if x < 0.
+ // Results are undefined if x = 0 and y <= 0.
+ if (x < 0.0f)
+ UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
+ else if (x == 0.0f && y <= 0.0f)
+ UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
+ else
+ resultArray[i].setFConst(powf(x, y));
+ }
+ }
+ else
+ UNREACHABLE();
}
+ break;
- tempNode = new TIntermConstantUnion(
- tempConstArray, TType(EbtBool, EbpUndefined, EvqConst));
- tempNode->setLine(getLine());
+ case EOpMod:
+ {
+ if (basicType == EbtFloat)
+ {
+ resultArray = new TConstantUnion[maxObjectSize];
+ for (size_t i = 0; i < maxObjectSize; i++)
+ {
+ float x = unionArrays[0][i].getFConst();
+ float y = unionArrays[1][i].getFConst();
+ resultArray[i].setFConst(x - y * floorf(x / y));
+ }
+ }
+ else
+ UNREACHABLE();
+ }
+ break;
- return tempNode;
+ case EOpMin:
+ {
+ resultArray = new TConstantUnion[maxObjectSize];
+ for (size_t i = 0; i < maxObjectSize; i++)
+ {
+ switch (basicType)
+ {
+ case EbtFloat:
+ resultArray[i].setFConst(std::min(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
+ break;
+ case EbtInt:
+ resultArray[i].setIConst(std::min(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
+ break;
+ case EbtUInt:
+ resultArray[i].setUConst(std::min(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+ }
+ }
+ break;
- case EOpNotEqual:
- if (getType().getBasicType() == EbtStruct)
+ case EOpMax:
{
- if (CompareStructure(node->getType(),
- node->getUnionArrayPointer(),
- unionArray))
+ resultArray = new TConstantUnion[maxObjectSize];
+ for (size_t i = 0; i < maxObjectSize; i++)
{
- boolNodeFlag = true;
+ switch (basicType)
+ {
+ case EbtFloat:
+ resultArray[i].setFConst(std::max(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
+ break;
+ case EbtInt:
+ resultArray[i].setIConst(std::max(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
+ break;
+ case EbtUInt:
+ resultArray[i].setUConst(std::max(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
}
}
- else
+ break;
+
+ case EOpStep:
{
- for (size_t i = 0; i < objectSize; i++)
+ if (basicType == EbtFloat)
{
- if (unionArray[i] == rightUnionArray[i])
+ resultArray = new TConstantUnion[maxObjectSize];
+ for (size_t i = 0; i < maxObjectSize; i++)
+ resultArray[i].setFConst(unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f : 1.0f);
+ }
+ else
+ UNREACHABLE();
+ }
+ break;
+
+ case EOpLessThan:
+ {
+ resultArray = new TConstantUnion[maxObjectSize];
+ for (size_t i = 0; i < maxObjectSize; i++)
+ {
+ switch (basicType)
{
- boolNodeFlag = true;
- break; // break out of for loop
+ case EbtFloat:
+ resultArray[i].setBConst(unionArrays[0][i].getFConst() < unionArrays[1][i].getFConst());
+ break;
+ case EbtInt:
+ resultArray[i].setBConst(unionArrays[0][i].getIConst() < unionArrays[1][i].getIConst());
+ break;
+ case EbtUInt:
+ resultArray[i].setBConst(unionArrays[0][i].getUConst() < unionArrays[1][i].getUConst());
+ break;
+ default:
+ UNREACHABLE();
+ break;
}
}
}
+ break;
+
+ case EOpLessThanEqual:
+ {
+ resultArray = new TConstantUnion[maxObjectSize];
+ for (size_t i = 0; i < maxObjectSize; i++)
+ {
+ switch (basicType)
+ {
+ case EbtFloat:
+ resultArray[i].setBConst(unionArrays[0][i].getFConst() <= unionArrays[1][i].getFConst());
+ break;
+ case EbtInt:
+ resultArray[i].setBConst(unionArrays[0][i].getIConst() <= unionArrays[1][i].getIConst());
+ break;
+ case EbtUInt:
+ resultArray[i].setBConst(unionArrays[0][i].getUConst() <= unionArrays[1][i].getUConst());
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+ }
+ }
+ break;
+
+ case EOpGreaterThan:
+ {
+ resultArray = new TConstantUnion[maxObjectSize];
+ for (size_t i = 0; i < maxObjectSize; i++)
+ {
+ switch (basicType)
+ {
+ case EbtFloat:
+ resultArray[i].setBConst(unionArrays[0][i].getFConst() > unionArrays[1][i].getFConst());
+ break;
+ case EbtInt:
+ resultArray[i].setBConst(unionArrays[0][i].getIConst() > unionArrays[1][i].getIConst());
+ break;
+ case EbtUInt:
+ resultArray[i].setBConst(unionArrays[0][i].getUConst() > unionArrays[1][i].getUConst());
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+ }
+ }
+ break;
+
+ case EOpGreaterThanEqual:
+ {
+ resultArray = new TConstantUnion[maxObjectSize];
+ for (size_t i = 0; i < maxObjectSize; i++)
+ {
+ switch (basicType)
+ {
+ case EbtFloat:
+ resultArray[i].setBConst(unionArrays[0][i].getFConst() >= unionArrays[1][i].getFConst());
+ break;
+ case EbtInt:
+ resultArray[i].setBConst(unionArrays[0][i].getIConst() >= unionArrays[1][i].getIConst());
+ break;
+ case EbtUInt:
+ resultArray[i].setBConst(unionArrays[0][i].getUConst() >= unionArrays[1][i].getUConst());
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+ }
+ }
+ break;
+
+ case EOpVectorEqual:
+ {
+ resultArray = new TConstantUnion[maxObjectSize];
+ for (size_t i = 0; i < maxObjectSize; i++)
+ {
+ switch (basicType)
+ {
+ case EbtFloat:
+ resultArray[i].setBConst(unionArrays[0][i].getFConst() == unionArrays[1][i].getFConst());
+ break;
+ case EbtInt:
+ resultArray[i].setBConst(unionArrays[0][i].getIConst() == unionArrays[1][i].getIConst());
+ break;
+ case EbtUInt:
+ resultArray[i].setBConst(unionArrays[0][i].getUConst() == unionArrays[1][i].getUConst());
+ break;
+ case EbtBool:
+ resultArray[i].setBConst(unionArrays[0][i].getBConst() == unionArrays[1][i].getBConst());
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+ }
+ }
+ break;
+
+ case EOpVectorNotEqual:
+ {
+ resultArray = new TConstantUnion[maxObjectSize];
+ for (size_t i = 0; i < maxObjectSize; i++)
+ {
+ switch (basicType)
+ {
+ case EbtFloat:
+ resultArray[i].setBConst(unionArrays[0][i].getFConst() != unionArrays[1][i].getFConst());
+ break;
+ case EbtInt:
+ resultArray[i].setBConst(unionArrays[0][i].getIConst() != unionArrays[1][i].getIConst());
+ break;
+ case EbtUInt:
+ resultArray[i].setBConst(unionArrays[0][i].getUConst() != unionArrays[1][i].getUConst());
+ break;
+ case EbtBool:
+ resultArray[i].setBConst(unionArrays[0][i].getBConst() != unionArrays[1][i].getBConst());
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+ }
+ }
+ break;
+
+ case EOpDistance:
+ if (basicType == EbtFloat)
+ {
+ TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
+ resultArray = new TConstantUnion();
+ for (size_t i = 0; i < maxObjectSize; i++)
+ {
+ float x = unionArrays[0][i].getFConst();
+ float y = unionArrays[1][i].getFConst();
+ distanceArray[i].setFConst(x - y);
+ }
+ resultArray->setFConst(VectorLength(distanceArray, maxObjectSize));
+ }
+ else
+ UNREACHABLE();
+ break;
+
+ case EOpDot:
+
+ if (basicType == EbtFloat)
+ {
+ resultArray = new TConstantUnion();
+ resultArray->setFConst(VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
+ }
+ else
+ UNREACHABLE();
+ break;
- tempConstArray = new ConstantUnion[1];
- if (!boolNodeFlag)
+ case EOpCross:
+ if (basicType == EbtFloat && maxObjectSize == 3)
{
- tempConstArray->setBConst(true);
+ resultArray = new TConstantUnion[maxObjectSize];
+ float x0 = unionArrays[0][0].getFConst();
+ float x1 = unionArrays[0][1].getFConst();
+ float x2 = unionArrays[0][2].getFConst();
+ float y0 = unionArrays[1][0].getFConst();
+ float y1 = unionArrays[1][1].getFConst();
+ float y2 = unionArrays[1][2].getFConst();
+ resultArray[0].setFConst(x1 * y2 - y1 * x2);
+ resultArray[1].setFConst(x2 * y0 - y2 * x0);
+ resultArray[2].setFConst(x0 * y1 - y0 * x1);
}
else
+ UNREACHABLE();
+ break;
+
+ case EOpReflect:
+ if (basicType == EbtFloat)
{
- tempConstArray->setBConst(false);
+ // genType reflect (genType I, genType N) :
+ // For the incident vector I and surface orientation N, returns the reflection direction:
+ // I - 2 * dot(N, I) * N.
+ resultArray = new TConstantUnion[maxObjectSize];
+ float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
+ for (size_t i = 0; i < maxObjectSize; i++)
+ {
+ float result = unionArrays[0][i].getFConst() -
+ 2.0f * dotProduct * unionArrays[1][i].getFConst();
+ resultArray[i].setFConst(result);
+ }
}
+ else
+ UNREACHABLE();
+ break;
- tempNode = new TIntermConstantUnion(
- tempConstArray, TType(EbtBool, EbpUndefined, EvqConst));
- tempNode->setLine(getLine());
+ case EOpMul:
+ if (basicType == EbtFloat && (*sequence)[0]->getAsTyped()->isMatrix() &&
+ (*sequence)[1]->getAsTyped()->isMatrix())
+ {
+ // Perform component-wise matrix multiplication.
+ resultArray = new TConstantUnion[maxObjectSize];
+ int size = (*sequence)[0]->getAsTyped()->getNominalSize();
+ angle::Matrix<float> result =
+ GetMatrix(unionArrays[0], size).compMult(GetMatrix(unionArrays[1], size));
+ SetUnionArrayFromMatrix(result, resultArray);
+ }
+ else
+ UNREACHABLE();
+ break;
- return tempNode;
+ case EOpOuterProduct:
+ if (basicType == EbtFloat)
+ {
+ size_t numRows = (*sequence)[0]->getAsTyped()->getType().getObjectSize();
+ size_t numCols = (*sequence)[1]->getAsTyped()->getType().getObjectSize();
+ resultArray = new TConstantUnion[numRows * numCols];
+ angle::Matrix<float> result =
+ GetMatrix(unionArrays[0], 1, static_cast<int>(numCols))
+ .outerProduct(GetMatrix(unionArrays[1], static_cast<int>(numRows), 1));
+ SetUnionArrayFromMatrix(result, resultArray);
+ }
+ else
+ UNREACHABLE();
+ break;
default:
- infoSink.info.message(
- EPrefixInternalError, getLine(),
- "Invalid operator for constant folding");
- return NULL;
+ UNREACHABLE();
+ // TODO: Add constant folding support for other built-in operations that take 2 parameters and not handled above.
+ return nullptr;
}
- tempNode = new TIntermConstantUnion(tempConstArray, returnType);
- tempNode->setLine(getLine());
-
- return tempNode;
}
- else
+ else if (paramsCount == 3)
{
//
- // Do unary operations
+ // Ternary built-in
//
- TIntermConstantUnion *newNode = 0;
- ConstantUnion* tempConstArray = new ConstantUnion[objectSize];
- for (size_t i = 0; i < objectSize; i++)
+ switch (op)
{
- switch(op)
+ case EOpClamp:
{
- case EOpNegative:
- switch (getType().getBasicType())
+ resultArray = new TConstantUnion[maxObjectSize];
+ for (size_t i = 0; i < maxObjectSize; i++)
{
- case EbtFloat:
- tempConstArray[i].setFConst(-unionArray[i].getFConst());
- break;
- case EbtInt:
- tempConstArray[i].setIConst(-unionArray[i].getIConst());
- break;
- case EbtUInt:
- tempConstArray[i].setUConst(static_cast<unsigned int>(
- -static_cast<int>(unionArray[i].getUConst())));
- break;
- default:
- infoSink.info.message(
- EPrefixInternalError, getLine(),
- "Unary operation not folded into constant");
- return NULL;
+ switch (basicType)
+ {
+ case EbtFloat:
+ {
+ float x = unionArrays[0][i].getFConst();
+ float min = unionArrays[1][i].getFConst();
+ float max = unionArrays[2][i].getFConst();
+ // Results are undefined if min > max.
+ if (min > max)
+ UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
+ else
+ resultArray[i].setFConst(gl::clamp(x, min, max));
+ }
+ break;
+ case EbtInt:
+ {
+ int x = unionArrays[0][i].getIConst();
+ int min = unionArrays[1][i].getIConst();
+ int max = unionArrays[2][i].getIConst();
+ // Results are undefined if min > max.
+ if (min > max)
+ UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
+ else
+ resultArray[i].setIConst(gl::clamp(x, min, max));
+ }
+ break;
+ case EbtUInt:
+ {
+ unsigned int x = unionArrays[0][i].getUConst();
+ unsigned int min = unionArrays[1][i].getUConst();
+ unsigned int max = unionArrays[2][i].getUConst();
+ // Results are undefined if min > max.
+ if (min > max)
+ UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
+ else
+ resultArray[i].setUConst(gl::clamp(x, min, max));
+ }
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
}
- break;
+ }
+ break;
- case EOpPositive:
- switch (getType().getBasicType())
+ case EOpMix:
+ {
+ if (basicType == EbtFloat)
{
- case EbtFloat:
- tempConstArray[i].setFConst(unionArray[i].getFConst());
- break;
- case EbtInt:
- tempConstArray[i].setIConst(unionArray[i].getIConst());
- break;
- case EbtUInt:
- tempConstArray[i].setUConst(static_cast<unsigned int>(
- static_cast<int>(unionArray[i].getUConst())));
- break;
- default:
- infoSink.info.message(
- EPrefixInternalError, getLine(),
- "Unary operation not folded into constant");
- return NULL;
+ resultArray = new TConstantUnion[maxObjectSize];
+ for (size_t i = 0; i < maxObjectSize; i++)
+ {
+ float x = unionArrays[0][i].getFConst();
+ float y = unionArrays[1][i].getFConst();
+ TBasicType type = (*sequence)[2]->getAsTyped()->getType().getBasicType();
+ if (type == EbtFloat)
+ {
+ // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
+ float a = unionArrays[2][i].getFConst();
+ resultArray[i].setFConst(x * (1.0f - a) + y * a);
+ }
+ else // 3rd parameter is EbtBool
+ {
+ ASSERT(type == EbtBool);
+ // Selects which vector each returned component comes from.
+ // For a component of a that is false, the corresponding component of x is returned.
+ // For a component of a that is true, the corresponding component of y is returned.
+ bool a = unionArrays[2][i].getBConst();
+ resultArray[i].setFConst(a ? y : x);
+ }
+ }
}
- break;
+ else
+ UNREACHABLE();
+ }
+ break;
- case EOpLogicalNot:
- // this code is written for possible future use,
- // will not get executed currently
- switch (getType().getBasicType())
+ case EOpSmoothStep:
+ {
+ if (basicType == EbtFloat)
{
- case EbtBool:
- tempConstArray[i].setBConst(!unionArray[i].getBConst());
- break;
- default:
- infoSink.info.message(
- EPrefixInternalError, getLine(),
- "Unary operation not folded into constant");
- return NULL;
+ resultArray = new TConstantUnion[maxObjectSize];
+ for (size_t i = 0; i < maxObjectSize; i++)
+ {
+ float edge0 = unionArrays[0][i].getFConst();
+ float edge1 = unionArrays[1][i].getFConst();
+ float x = unionArrays[2][i].getFConst();
+ // Results are undefined if edge0 >= edge1.
+ if (edge0 >= edge1)
+ {
+ UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
+ }
+ else
+ {
+ // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
+ // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
+ float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
+ resultArray[i].setFConst(t * t * (3.0f - 2.0f * t));
+ }
+ }
}
- break;
+ else
+ UNREACHABLE();
+ }
+ break;
- case EOpBitwiseNot:
- switch (getType().getBasicType())
+ case EOpFaceForward:
+ if (basicType == EbtFloat)
+ {
+ // genType faceforward(genType N, genType I, genType Nref) :
+ // If dot(Nref, I) < 0 return N, otherwise return -N.
+ resultArray = new TConstantUnion[maxObjectSize];
+ float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize);
+ for (size_t i = 0; i < maxObjectSize; i++)
{
- 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;
+ if (dotProduct < 0)
+ resultArray[i].setFConst(unionArrays[0][i].getFConst());
+ else
+ resultArray[i].setFConst(-unionArrays[0][i].getFConst());
}
- break;
+ }
+ else
+ UNREACHABLE();
+ break;
- default:
- return NULL;
+ case EOpRefract:
+ if (basicType == EbtFloat)
+ {
+ // genType refract(genType I, genType N, float eta) :
+ // For the incident vector I and surface normal N, and the ratio of indices of refraction eta,
+ // return the refraction vector. The result is computed by
+ // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
+ // if (k < 0.0)
+ // return genType(0.0)
+ // else
+ // return eta * I - (eta * dot(N, I) + sqrt(k)) * N
+ resultArray = new TConstantUnion[maxObjectSize];
+ float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
+ for (size_t i = 0; i < maxObjectSize; i++)
+ {
+ float eta = unionArrays[2][i].getFConst();
+ float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
+ if (k < 0.0f)
+ resultArray[i].setFConst(0.0f);
+ else
+ resultArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
+ (eta * dotProduct + sqrtf(k)) * unionArrays[1][i].getFConst());
+ }
}
+ else
+ UNREACHABLE();
+ break;
+
+ default:
+ UNREACHABLE();
+ // TODO: Add constant folding support for other built-in operations that take 3 parameters and not handled above.
+ return nullptr;
}
- newNode = new TIntermConstantUnion(tempConstArray, getType());
- newNode->setLine(getLine());
- return newNode;
}
+ return resultArray;
}
// static
@@ -1209,26 +2606,59 @@ TString TIntermTraverser::hash(const TString &name, ShHashFunction64 hashFunctio
void TIntermTraverser::updateTree()
{
+ for (size_t ii = 0; ii < mInsertions.size(); ++ii)
+ {
+ const NodeInsertMultipleEntry &insertion = mInsertions[ii];
+ ASSERT(insertion.parent);
+ if (!insertion.insertionsAfter.empty())
+ {
+ bool inserted = insertion.parent->insertChildNodes(insertion.position + 1,
+ insertion.insertionsAfter);
+ ASSERT(inserted);
+ UNUSED_ASSERTION_VARIABLE(inserted);
+ }
+ if (!insertion.insertionsBefore.empty())
+ {
+ bool inserted =
+ insertion.parent->insertChildNodes(insertion.position, insertion.insertionsBefore);
+ ASSERT(inserted);
+ UNUSED_ASSERTION_VARIABLE(inserted);
+ }
+ }
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);
+ const NodeUpdateEntry &replacement = mReplacements[ii];
+ ASSERT(replacement.parent);
+ bool replaced = replacement.parent->replaceChildNode(
+ replacement.original, replacement.replacement);
ASSERT(replaced);
+ UNUSED_ASSERTION_VARIABLE(replaced);
- if (!entry.originalBecomesChildOfReplacement)
+ if (!replacement.originalBecomesChildOfReplacement)
{
// In AST traversing, a parent is visited before its children.
- // After we replace a node, if an immediate child is to
+ // After we replace a node, if its 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;
+ NodeUpdateEntry &replacement2 = mReplacements[jj];
+ if (replacement2.parent == replacement.original)
+ replacement2.parent = replacement.replacement;
}
}
}
+ for (size_t ii = 0; ii < mMultiReplacements.size(); ++ii)
+ {
+ const NodeReplaceWithMultipleEntry &replacement = mMultiReplacements[ii];
+ ASSERT(replacement.parent);
+ bool replaced = replacement.parent->replaceChildNodeWithMultiple(
+ replacement.original, replacement.replacements);
+ ASSERT(replaced);
+ UNUSED_ASSERTION_VARIABLE(replaced);
+ }
+
+ mInsertions.clear();
+ mReplacements.clear();
+ mMultiReplacements.clear();
}
diff --git a/src/3rdparty/angle/src/compiler/translator/IntermNode.h b/src/3rdparty/angle/src/compiler/translator/IntermNode.h
index 9f732cbb00..ad500e2b1f 100644
--- a/src/3rdparty/angle/src/compiler/translator/IntermNode.h
+++ b/src/3rdparty/angle/src/compiler/translator/IntermNode.h
@@ -23,9 +23,9 @@
#include "common/angleutils.h"
#include "compiler/translator/Common.h"
-#include "compiler/translator/Types.h"
#include "compiler/translator/ConstantUnion.h"
#include "compiler/translator/Operator.h"
+#include "compiler/translator/Types.h"
class TIntermTraverser;
class TIntermAggregate;
@@ -42,10 +42,33 @@ class TInfoSink;
class TInfoSinkBase;
class TIntermRaw;
+class TSymbolTable;
+
+// Encapsulate an identifier string and track whether it is coming from the original shader code
+// (not internal) or from ANGLE (internal). Usually internal names shouldn't be decorated or hashed.
+class TName
+{
+ public:
+ POOL_ALLOCATOR_NEW_DELETE();
+ explicit TName(const TString &name) : mName(name), mIsInternal(false) {}
+ TName() : mName(), mIsInternal(false) {}
+ TName(const TName &) = default;
+ TName &operator=(const TName &) = default;
+
+ const TString &getString() const { return mName; }
+ void setString(const TString &string) { mName = string; }
+ bool isInternal() const { return mIsInternal; }
+ void setInternal(bool isInternal) { mIsInternal = isInternal; }
+
+ private:
+ TString mName;
+ bool mIsInternal;
+};
+
//
// Base class for the tree nodes
//
-class TIntermNode
+class TIntermNode : angle::NonCopyable
{
public:
POOL_ALLOCATOR_NEW_DELETE();
@@ -99,7 +122,10 @@ class TIntermTyped : public TIntermNode
{
public:
TIntermTyped(const TType &t) : mType(t) { }
- virtual TIntermTyped *getAsTyped() { return this; }
+
+ virtual TIntermTyped *deepCopy() const = 0;
+
+ TIntermTyped *getAsTyped() override { return this; }
virtual bool hasSideEffects() const = 0;
@@ -123,13 +149,14 @@ class TIntermTyped : public TIntermNode
bool isScalar() const { return mType.isScalar(); }
bool isScalarInt() const { return mType.isScalarInt(); }
const char *getBasicString() const { return mType.getBasicString(); }
- const char *getQualifierString() const { return mType.getQualifierString(); }
TString getCompleteString() const { return mType.getCompleteString(); }
int getArraySize() const { return mType.getArraySize(); }
protected:
TType mType;
+
+ TIntermTyped(const TIntermTyped &node);
};
//
@@ -146,25 +173,23 @@ class TIntermLoop : public TIntermNode
{
public:
TIntermLoop(TLoopType type,
- TIntermNode *init, TIntermTyped *cond, TIntermTyped *expr,
- TIntermNode *body)
- : mType(type),
- mInit(init),
- mCond(cond),
- mExpr(expr),
- mBody(body),
- mUnrollFlag(false) { }
+ TIntermNode *init,
+ TIntermTyped *cond,
+ TIntermTyped *expr,
+ TIntermAggregate *body)
+ : mType(type), mInit(init), mCond(cond), mExpr(expr), mBody(body), mUnrollFlag(false)
+ {
+ }
- virtual TIntermLoop *getAsLoopNode() { return this; }
- virtual void traverse(TIntermTraverser *);
- virtual bool replaceChildNode(
- TIntermNode *original, TIntermNode *replacement);
+ TIntermLoop *getAsLoopNode() override { return this; }
+ void traverse(TIntermTraverser *it) override;
+ bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
TLoopType getType() const { return mType; }
TIntermNode *getInit() { return mInit; }
TIntermTyped *getCondition() { return mCond; }
TIntermTyped *getExpression() { return mExpr; }
- TIntermNode *getBody() { return mBody; }
+ TIntermAggregate *getBody() { return mBody; }
void setUnrollFlag(bool flag) { mUnrollFlag = flag; }
bool getUnrollFlag() const { return mUnrollFlag; }
@@ -174,7 +199,7 @@ class TIntermLoop : public TIntermNode
TIntermNode *mInit; // for-loop initialization
TIntermTyped *mCond; // loop exit condition
TIntermTyped *mExpr; // for-loop expression
- TIntermNode *mBody; // loop body
+ TIntermAggregate *mBody; // loop body
bool mUnrollFlag; // Whether the loop should be unrolled or not.
};
@@ -189,9 +214,8 @@ class TIntermBranch : public TIntermNode
: mFlowOp(op),
mExpression(e) { }
- virtual void traverse(TIntermTraverser *);
- virtual bool replaceChildNode(
- TIntermNode *original, TIntermNode *replacement);
+ void traverse(TIntermTraverser *it) override;
+ bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
TOperator getFlowOp() { return mFlowOp; }
TIntermTyped* getExpression() { return mExpression; }
@@ -211,26 +235,32 @@ class TIntermSymbol : public TIntermTyped
// If sym comes from per process globalpoolallocator, then it causes increased memory usage
// per compile it is essential to use "symbol = sym" to assign to symbol
TIntermSymbol(int id, const TString &symbol, const TType &type)
- : TIntermTyped(type),
- mId(id)
+ : TIntermTyped(type), mId(id), mSymbol(symbol)
{
- mSymbol = symbol;
}
- virtual bool hasSideEffects() const { return false; }
+ TIntermTyped *deepCopy() const override { return new TIntermSymbol(*this); }
+
+ bool hasSideEffects() const override { return false; }
int getId() const { return mId; }
- const TString &getSymbol() const { return mSymbol; }
+ const TString &getSymbol() const { return mSymbol.getString(); }
+ const TName &getName() const { return mSymbol; }
void setId(int newId) { mId = newId; }
- virtual void traverse(TIntermTraverser *);
- virtual TIntermSymbol *getAsSymbolNode() { return this; }
- virtual bool replaceChildNode(TIntermNode *, TIntermNode *) { return false; }
+ void setInternal(bool internal) { mSymbol.setInternal(internal); }
+
+ void traverse(TIntermTraverser *it) override;
+ TIntermSymbol *getAsSymbolNode() override { return this; }
+ bool replaceChildNode(TIntermNode *, TIntermNode *) override { return false; }
protected:
int mId;
- TString mSymbol;
+ TName mSymbol;
+
+ private:
+ TIntermSymbol(const TIntermSymbol &) = default; // Note: not deleted, just private!
};
// A Raw node stores raw code, that the translator will insert verbatim
@@ -242,30 +272,46 @@ class TIntermRaw : public TIntermTyped
TIntermRaw(const TType &type, const TString &rawText)
: TIntermTyped(type),
mRawText(rawText) { }
+ TIntermRaw(const TIntermRaw &) = delete;
+
+ TIntermTyped *deepCopy() const override
+ {
+ UNREACHABLE();
+ return nullptr;
+ }
- virtual bool hasSideEffects() const { return false; }
+ bool hasSideEffects() const override { return false; }
TString getRawText() const { return mRawText; }
- virtual void traverse(TIntermTraverser *);
+ void traverse(TIntermTraverser *it) override;
- virtual TIntermRaw *getAsRawNode() { return this; }
- virtual bool replaceChildNode(TIntermNode *, TIntermNode *) { return false; }
+ TIntermRaw *getAsRawNode() override { return this; }
+ bool replaceChildNode(TIntermNode *, TIntermNode *) override { return false; }
protected:
TString mRawText;
};
+// Constant folded node.
+// Note that nodes may be constant folded and not be constant expressions with the EvqConst
+// qualifier. This happens for example when the following expression is processed:
+// "true ? 1.0 : non_constant"
+// Other nodes than TIntermConstantUnion may also be constant expressions.
+//
class TIntermConstantUnion : public TIntermTyped
{
public:
- TIntermConstantUnion(ConstantUnion *unionPointer, const TType &type)
- : TIntermTyped(type),
- mUnionArrayPointer(unionPointer) { }
+ TIntermConstantUnion(const TConstantUnion *unionPointer, const TType &type)
+ : TIntermTyped(type), mUnionArrayPointer(unionPointer)
+ {
+ }
+
+ TIntermTyped *deepCopy() const override { return new TIntermConstantUnion(*this); }
- virtual bool hasSideEffects() const { return false; }
+ bool hasSideEffects() const override { return false; }
- ConstantUnion *getUnionArrayPointer() const { return mUnionArrayPointer; }
+ const TConstantUnion *getUnionArrayPointer() const { return mUnionArrayPointer; }
int getIConst(size_t index) const
{
@@ -284,14 +330,33 @@ class TIntermConstantUnion : public TIntermTyped
return mUnionArrayPointer ? mUnionArrayPointer[index].getBConst() : false;
}
- virtual TIntermConstantUnion *getAsConstantUnion() { return this; }
- virtual void traverse(TIntermTraverser *);
- virtual bool replaceChildNode(TIntermNode *, TIntermNode *) { return false; }
+ void replaceConstantUnion(const TConstantUnion *safeConstantUnion)
+ {
+ // Previous union pointer freed on pool deallocation.
+ mUnionArrayPointer = safeConstantUnion;
+ }
- TIntermTyped *fold(TOperator, TIntermTyped *, TInfoSink &);
+ TIntermConstantUnion *getAsConstantUnion() override { return this; }
+ void traverse(TIntermTraverser *it) override;
+ bool replaceChildNode(TIntermNode *, TIntermNode *) override { return false; }
+
+ TConstantUnion *foldBinary(TOperator op, TIntermConstantUnion *rightNode, TInfoSink &infoSink);
+ TConstantUnion *foldUnaryWithDifferentReturnType(TOperator op, TInfoSink &infoSink);
+ TConstantUnion *foldUnaryWithSameReturnType(TOperator op, TInfoSink &infoSink);
+
+ static TConstantUnion *FoldAggregateConstructor(TIntermAggregate *aggregate,
+ TInfoSink &infoSink);
+ static TConstantUnion *FoldAggregateBuiltIn(TIntermAggregate *aggregate, TInfoSink &infoSink);
protected:
- ConstantUnion *mUnionArrayPointer;
+ // Same data may be shared between multiple constant unions, so it can't be modified.
+ const TConstantUnion *mUnionArrayPointer;
+
+ private:
+ typedef float(*FloatTypeUnaryFunc) (float);
+ bool foldFloatTypeUnary(const TConstantUnion &parameter, FloatTypeUnaryFunc builtinFunc, TInfoSink &infoSink, TConstantUnion *result) const;
+
+ TIntermConstantUnion(const TIntermConstantUnion &node); // Note: not deleted, just private!
};
//
@@ -304,9 +369,10 @@ class TIntermOperator : public TIntermTyped
void setOp(TOperator op) { mOp = op; }
bool isAssignment() const;
+ bool isMultiplication() const;
bool isConstructor() const;
- virtual bool hasSideEffects() const { return isAssignment(); }
+ bool hasSideEffects() const override { return isAssignment(); }
protected:
TIntermOperator(TOperator op)
@@ -316,6 +382,8 @@ class TIntermOperator : public TIntermTyped
: TIntermTyped(type),
mOp(op) {}
+ TIntermOperator(const TIntermOperator &) = default;
+
TOperator mOp;
};
@@ -329,12 +397,13 @@ class TIntermBinary : public TIntermOperator
: TIntermOperator(op),
mAddIndexClamp(false) {}
- virtual TIntermBinary *getAsBinaryNode() { return this; }
- virtual void traverse(TIntermTraverser *);
- virtual bool replaceChildNode(
- TIntermNode *original, TIntermNode *replacement);
+ TIntermTyped *deepCopy() const override { return new TIntermBinary(*this); }
+
+ TIntermBinary *getAsBinaryNode() override { return this; };
+ void traverse(TIntermTraverser *it) override;
+ bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
- virtual bool hasSideEffects() const
+ bool hasSideEffects() const override
{
return isAssignment() || mLeft->hasSideEffects() || mRight->hasSideEffects();
}
@@ -344,6 +413,7 @@ class TIntermBinary : public TIntermOperator
TIntermTyped *getLeft() const { return mLeft; }
TIntermTyped *getRight() const { return mRight; }
bool promote(TInfoSink &);
+ TIntermTyped *fold(TInfoSink &infoSink);
void setAddIndexClamp() { mAddIndexClamp = true; }
bool getAddIndexClamp() { return mAddIndexClamp; }
@@ -354,6 +424,9 @@ class TIntermBinary : public TIntermOperator
// If set to true, wrap any EOpIndexIndirect with a clamp to bounds.
bool mAddIndexClamp;
+
+ private:
+ TIntermBinary(const TIntermBinary &node); // Note: not deleted, just private!
};
//
@@ -371,19 +444,18 @@ class TIntermUnary : public TIntermOperator
mOperand(NULL),
mUseEmulatedFunction(false) {}
- virtual void traverse(TIntermTraverser *);
- virtual TIntermUnary *getAsUnaryNode() { return this; }
- virtual bool replaceChildNode(
- TIntermNode *original, TIntermNode *replacement);
+ TIntermTyped *deepCopy() const override { return new TIntermUnary(*this); }
- virtual bool hasSideEffects() const
- {
- return isAssignment() || mOperand->hasSideEffects();
- }
+ void traverse(TIntermTraverser *it) override;
+ TIntermUnary *getAsUnaryNode() override { return this; }
+ bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
+
+ bool hasSideEffects() const override { return isAssignment() || mOperand->hasSideEffects(); }
void setOperand(TIntermTyped *operand) { mOperand = operand; }
TIntermTyped *getOperand() { return mOperand; }
void promote(const TType *funcReturnType);
+ TIntermTyped *fold(TInfoSink &infoSink);
void setUseEmulatedFunction() { mUseEmulatedFunction = true; }
bool getUseEmulatedFunction() { return mUseEmulatedFunction; }
@@ -394,6 +466,9 @@ class TIntermUnary : public TIntermOperator
// If set to true, replace the built-in function call with an emulated one
// to work around driver bugs.
bool mUseEmulatedFunction;
+
+ private:
+ TIntermUnary(const TIntermUnary &node); // note: not deleted, just private!
};
typedef TVector<TIntermNode *> TIntermSequence;
@@ -408,52 +483,68 @@ class TIntermAggregate : public TIntermOperator
TIntermAggregate()
: TIntermOperator(EOpNull),
mUserDefined(false),
- mUseEmulatedFunction(false) { }
+ mUseEmulatedFunction(false),
+ mGotPrecisionFromChildren(false)
+ {
+ }
TIntermAggregate(TOperator op)
: TIntermOperator(op),
- mUseEmulatedFunction(false) { }
+ mUseEmulatedFunction(false),
+ mGotPrecisionFromChildren(false)
+ {
+ }
~TIntermAggregate() { }
- virtual TIntermAggregate *getAsAggregate() { return this; }
- virtual void traverse(TIntermTraverser *);
- virtual bool replaceChildNode(
- TIntermNode *original, TIntermNode *replacement);
+ // Note: only supported for nodes that can be a part of an expression.
+ TIntermTyped *deepCopy() const override { return new TIntermAggregate(*this); }
+ TIntermAggregate *getAsAggregate() override { return this; }
+ void traverse(TIntermTraverser *it) override;
+ bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
+ bool replaceChildNodeWithMultiple(TIntermNode *original, TIntermSequence replacements);
+ bool insertChildNodes(TIntermSequence::size_type position, TIntermSequence insertions);
// Conservatively assume function calls and other aggregate operators have side-effects
- virtual bool hasSideEffects() const { return true; }
+ bool hasSideEffects() const override { return true; }
+ TIntermTyped *fold(TInfoSink &infoSink);
TIntermSequence *getSequence() { return &mSequence; }
- void setName(const TString &name) { mName = name; }
- const TString &getName() const { return mName; }
+ void setNameObj(const TName &name) { mName = name; }
+ const TName &getNameObj() const { return mName; }
+
+ void setName(const TString &name) { mName.setString(name); }
+ const TString &getName() const { return mName.getString(); }
void setUserDefined() { mUserDefined = true; }
bool isUserDefined() const { return mUserDefined; }
- void setOptimize(bool optimize) { mOptimize = optimize; }
- bool getOptimize() const { return mOptimize; }
- void setDebug(bool debug) { mDebug = debug; }
- bool getDebug() const { return mDebug; }
+ void setFunctionId(int functionId) { mFunctionId = functionId; }
+ int getFunctionId() const { return mFunctionId; }
void setUseEmulatedFunction() { mUseEmulatedFunction = true; }
bool getUseEmulatedFunction() { return mUseEmulatedFunction; }
+ bool areChildrenConstQualified();
void setPrecisionFromChildren();
void setBuiltInFunctionPrecision();
+ // Returns true if changing parameter precision may affect the return value.
+ bool gotPrecisionFromChildren() const { return mGotPrecisionFromChildren; }
+
protected:
- TIntermAggregate(const TIntermAggregate &); // disallow copy constructor
- TIntermAggregate &operator=(const TIntermAggregate &); // disallow assignment operator
TIntermSequence mSequence;
- TString mName;
+ TName mName;
bool mUserDefined; // used for user defined function names
-
- bool mOptimize;
- bool mDebug;
+ int mFunctionId;
// If set to true, replace the built-in function call with an emulated one
// to work around driver bugs.
bool mUseEmulatedFunction;
+
+ bool mGotPrecisionFromChildren;
+
+ private:
+ TIntermAggregate(const TIntermAggregate &node); // note: not deleted, just private!
};
//
@@ -474,23 +565,28 @@ class TIntermSelection : public TIntermTyped
mTrueBlock(trueB),
mFalseBlock(falseB) {}
- virtual void traverse(TIntermTraverser *);
- virtual bool replaceChildNode(
- TIntermNode *original, TIntermNode *replacement);
+ // Note: only supported for ternary operator nodes.
+ TIntermTyped *deepCopy() const override { return new TIntermSelection(*this); }
+
+ void traverse(TIntermTraverser *it) override;
+ bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
// Conservatively assume selections have side-effects
- virtual bool hasSideEffects() const { return true; }
+ bool hasSideEffects() const override { return true; }
bool usesTernaryOperator() const { return getBasicType() != EbtVoid; }
TIntermNode *getCondition() const { return mCondition; }
TIntermNode *getTrueBlock() const { return mTrueBlock; }
TIntermNode *getFalseBlock() const { return mFalseBlock; }
- TIntermSelection *getAsSelectionNode() { return this; }
+ TIntermSelection *getAsSelectionNode() override { return this; }
-protected:
+ protected:
TIntermTyped *mCondition;
TIntermNode *mTrueBlock;
TIntermNode *mFalseBlock;
+
+ private:
+ TIntermSelection(const TIntermSelection &node); // Note: not deleted, just private!
};
//
@@ -512,6 +608,7 @@ class TIntermSwitch : public TIntermNode
TIntermSwitch *getAsSwitchNode() override { return this; }
+ TIntermTyped *getInit() { return mInit; }
TIntermAggregate *getStatementList() { return mStatementList; }
void setStatementList(TIntermAggregate *statementList) { mStatementList = statementList; }
@@ -553,9 +650,12 @@ enum Visit
};
//
-// For traversing the tree. User should derive from this,
-// put their traversal specific data in it, and then pass
-// it to a Traverse method.
+// For traversing the tree. User should derive from this class overriding the visit functions,
+// and then pass an object of the subclass to a traverse method of a node.
+//
+// The traverse*() functions may also be overridden do other bookkeeping on the tree to provide
+// contextual information to the visit functions, such as whether the node is the target of an
+// assignment.
//
// 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.
@@ -564,31 +664,59 @@ class TIntermTraverser : angle::NonCopyable
{
public:
POOL_ALLOCATOR_NEW_DELETE();
- // TODO(zmo): remove default values.
- TIntermTraverser(bool preVisit = true, bool inVisit = false, bool postVisit = false,
- bool rightToLeft = false)
+ TIntermTraverser(bool preVisit, bool inVisit, bool postVisit)
: preVisit(preVisit),
inVisit(inVisit),
postVisit(postVisit),
- rightToLeft(rightToLeft),
mDepth(0),
- mMaxDepth(0) {}
+ mMaxDepth(0),
+ mTemporaryIndex(nullptr)
+ {
+ }
virtual ~TIntermTraverser() {}
- virtual void visitSymbol(TIntermSymbol *) {}
- virtual void visitRaw(TIntermRaw *) {}
- virtual void visitConstantUnion(TIntermConstantUnion *) {}
- virtual bool visitBinary(Visit, TIntermBinary *) { return true; }
- virtual bool visitUnary(Visit, TIntermUnary *) { return true; }
- virtual bool visitSelection(Visit, TIntermSelection *) { return true; }
- virtual bool 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; }
+ virtual void visitSymbol(TIntermSymbol *node) {}
+ virtual void visitRaw(TIntermRaw *node) {}
+ virtual void visitConstantUnion(TIntermConstantUnion *node) {}
+ virtual bool visitBinary(Visit visit, TIntermBinary *node) { return true; }
+ virtual bool visitUnary(Visit visit, TIntermUnary *node) { return true; }
+ virtual bool visitSelection(Visit visit, TIntermSelection *node) { return true; }
+ virtual bool visitSwitch(Visit visit, TIntermSwitch *node) { return true; }
+ virtual bool visitCase(Visit visit, TIntermCase *node) { return true; }
+ virtual bool visitAggregate(Visit visit, TIntermAggregate *node) { return true; }
+ virtual bool visitLoop(Visit visit, TIntermLoop *node) { return true; }
+ virtual bool visitBranch(Visit visit, TIntermBranch *node) { return true; }
+
+ // The traverse functions contain logic for iterating over the children of the node
+ // and calling the visit functions in the appropriate places. They also track some
+ // context that may be used by the visit functions.
+ virtual void traverseSymbol(TIntermSymbol *node);
+ virtual void traverseRaw(TIntermRaw *node);
+ virtual void traverseConstantUnion(TIntermConstantUnion *node);
+ virtual void traverseBinary(TIntermBinary *node);
+ virtual void traverseUnary(TIntermUnary *node);
+ virtual void traverseSelection(TIntermSelection *node);
+ virtual void traverseSwitch(TIntermSwitch *node);
+ virtual void traverseCase(TIntermCase *node);
+ virtual void traverseAggregate(TIntermAggregate *node);
+ virtual void traverseLoop(TIntermLoop *node);
+ virtual void traverseBranch(TIntermBranch *node);
int getMaxDepth() const { return mMaxDepth; }
+ // Return the original name if hash function pointer is NULL;
+ // otherwise return the hashed name.
+ static TString hash(const TString &name, ShHashFunction64 hashFunction);
+
+ // If traversers need to replace nodes, they can add the replacements in
+ // mReplacements/mMultiReplacements during traversal and the user of the traverser should call
+ // this function after traversal to perform them.
+ void updateTree();
+
+ // Start creating temporary symbols from the given temporary symbol index + 1.
+ void useTemporaryIndex(unsigned int *temporaryIndex);
+
+ protected:
void incrementDepth(TIntermNode *current)
{
mDepth++;
@@ -607,27 +735,26 @@ class TIntermTraverser : angle::NonCopyable
return mPath.size() == 0 ? NULL : mPath.back();
}
- // Return the original name if hash function pointer is NULL;
- // otherwise return the hashed name.
- static TString hash(const TString& name, ShHashFunction64 hashFunction);
+ void pushParentBlock(TIntermAggregate *node);
+ void incrementParentBlockPos();
+ void popParentBlock();
+
+ bool parentNodeIsBlock()
+ {
+ return !mParentBlockStack.empty() && getParentNode() == mParentBlockStack.back().node;
+ }
const bool preVisit;
const bool inVisit;
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<TIntermNode *> mPath;
+ // To replace a single node with another on the parent node
struct NodeUpdateEntry
{
NodeUpdateEntry(TIntermNode *_parent,
@@ -645,9 +772,166 @@ class TIntermTraverser : angle::NonCopyable
bool originalBecomesChildOfReplacement;
};
+ // To replace a single node with multiple nodes on the parent aggregate node
+ struct NodeReplaceWithMultipleEntry
+ {
+ NodeReplaceWithMultipleEntry(TIntermAggregate *_parent, TIntermNode *_original, TIntermSequence _replacements)
+ : parent(_parent),
+ original(_original),
+ replacements(_replacements)
+ {
+ }
+
+ TIntermAggregate *parent;
+ TIntermNode *original;
+ TIntermSequence replacements;
+ };
+
+ // To insert multiple nodes on the parent aggregate node
+ struct NodeInsertMultipleEntry
+ {
+ NodeInsertMultipleEntry(TIntermAggregate *_parent,
+ TIntermSequence::size_type _position,
+ TIntermSequence _insertionsBefore,
+ TIntermSequence _insertionsAfter)
+ : parent(_parent),
+ position(_position),
+ insertionsBefore(_insertionsBefore),
+ insertionsAfter(_insertionsAfter)
+ {
+ }
+
+ TIntermAggregate *parent;
+ TIntermSequence::size_type position;
+ TIntermSequence insertionsBefore;
+ TIntermSequence insertionsAfter;
+ };
+
// During traversing, save all the changes that need to happen into
- // mReplacements, then do them by calling updateTree().
+ // mReplacements/mMultiReplacements, then do them by calling updateTree().
+ // Multi replacements are processed after single replacements.
std::vector<NodeUpdateEntry> mReplacements;
+ std::vector<NodeReplaceWithMultipleEntry> mMultiReplacements;
+ std::vector<NodeInsertMultipleEntry> mInsertions;
+
+ // Helper to insert statements in the parent block (sequence) of the node currently being traversed.
+ // The statements will be inserted before the node being traversed once updateTree is called.
+ // Should only be called during PreVisit or PostVisit from sequence nodes.
+ // Note that inserting more than one set of nodes to the same parent node on a single updateTree call is not
+ // supported.
+ void insertStatementsInParentBlock(const TIntermSequence &insertions);
+
+ // Same as above, but supports simultaneous insertion of statements before and after the node
+ // currently being traversed.
+ void insertStatementsInParentBlock(const TIntermSequence &insertionsBefore,
+ const TIntermSequence &insertionsAfter);
+
+ // Helper to create a temporary symbol node with the given qualifier.
+ TIntermSymbol *createTempSymbol(const TType &type, TQualifier qualifier);
+ // Helper to create a temporary symbol node.
+ TIntermSymbol *createTempSymbol(const TType &type);
+ // Create a node that declares but doesn't initialize a temporary symbol.
+ TIntermAggregate *createTempDeclaration(const TType &type);
+ // Create a node that initializes the current temporary symbol with initializer having the given qualifier.
+ TIntermAggregate *createTempInitDeclaration(TIntermTyped *initializer, TQualifier qualifier);
+ // Create a node that initializes the current temporary symbol with initializer.
+ TIntermAggregate *createTempInitDeclaration(TIntermTyped *initializer);
+ // Create a node that assigns rightNode to the current temporary symbol.
+ TIntermBinary *createTempAssignment(TIntermTyped *rightNode);
+ // Increment temporary symbol index.
+ void nextTemporaryIndex();
+
+ private:
+ struct ParentBlock
+ {
+ ParentBlock(TIntermAggregate *nodeIn, TIntermSequence::size_type posIn)
+ : node(nodeIn),
+ pos(posIn)
+ {
+ }
+
+ TIntermAggregate *node;
+ TIntermSequence::size_type pos;
+ };
+ // All the code blocks from the root to the current node's parent during traversal.
+ std::vector<ParentBlock> mParentBlockStack;
+
+ unsigned int *mTemporaryIndex;
+};
+
+// Traverser parent class that tracks where a node is a destination of a write operation and so is
+// required to be an l-value.
+class TLValueTrackingTraverser : public TIntermTraverser
+{
+ public:
+ TLValueTrackingTraverser(bool preVisit,
+ bool inVisit,
+ bool postVisit,
+ const TSymbolTable &symbolTable,
+ int shaderVersion)
+ : TIntermTraverser(preVisit, inVisit, postVisit),
+ mOperatorRequiresLValue(false),
+ mInFunctionCallOutParameter(false),
+ mSymbolTable(symbolTable),
+ mShaderVersion(shaderVersion)
+ {
+ }
+ virtual ~TLValueTrackingTraverser() {}
+
+ void traverseBinary(TIntermBinary *node) override;
+ void traverseUnary(TIntermUnary *node) override;
+ void traverseAggregate(TIntermAggregate *node) override;
+
+ protected:
+ bool isLValueRequiredHere() const
+ {
+ return mOperatorRequiresLValue || mInFunctionCallOutParameter;
+ }
+
+ // Return true if the prototype or definition of the function being called has been encountered
+ // during traversal.
+ bool isInFunctionMap(const TIntermAggregate *callNode) const;
+
+ private:
+ // Track whether an l-value is required in the node that is currently being traversed by the
+ // surrounding operator.
+ // Use isLValueRequiredHere to check all conditions which require an l-value.
+ void setOperatorRequiresLValue(bool lValueRequired)
+ {
+ mOperatorRequiresLValue = lValueRequired;
+ }
+ bool operatorRequiresLValue() const { return mOperatorRequiresLValue; }
+
+ // Add a function encountered during traversal to the function map.
+ void addToFunctionMap(const TName &name, TIntermSequence *paramSequence);
+
+ // Return the parameters sequence from the function definition or prototype.
+ TIntermSequence *getFunctionParameters(const TIntermAggregate *callNode);
+
+ // Track whether an l-value is required inside a function call.
+ void setInFunctionCallOutParameter(bool inOutParameter);
+ bool isInFunctionCallOutParameter() const;
+
+ bool mOperatorRequiresLValue;
+ bool mInFunctionCallOutParameter;
+
+ struct TNameComparator
+ {
+ bool operator()(const TName &a, const TName &b) const
+ {
+ int compareResult = a.getString().compare(b.getString());
+ if (compareResult != 0)
+ return compareResult < 0;
+ // Internal functions may have same names as non-internal functions.
+ return !a.isInternal() && b.isInternal();
+ }
+ };
+
+ // Map from mangled function names to their parameter sequences
+ TMap<TName, TIntermSequence *, TNameComparator> mFunctionMap;
+
+ const TSymbolTable &mSymbolTable;
+ const int mShaderVersion;
};
//
@@ -659,15 +943,15 @@ class TMaxDepthTraverser : public TIntermTraverser
public:
POOL_ALLOCATOR_NEW_DELETE();
TMaxDepthTraverser(int depthLimit)
- : TIntermTraverser(true, true, false, false),
+ : TIntermTraverser(true, true, false),
mDepthLimit(depthLimit) { }
- virtual bool visitBinary(Visit, TIntermBinary *) { return depthCheck(); }
- virtual bool visitUnary(Visit, TIntermUnary *) { return depthCheck(); }
- virtual bool visitSelection(Visit, TIntermSelection *) { return depthCheck(); }
- virtual bool visitAggregate(Visit, TIntermAggregate *) { return depthCheck(); }
- virtual bool visitLoop(Visit, TIntermLoop *) { return depthCheck(); }
- virtual bool visitBranch(Visit, TIntermBranch *) { return depthCheck(); }
+ bool visitBinary(Visit, TIntermBinary *) override { return depthCheck(); }
+ bool visitUnary(Visit, TIntermUnary *) override { return depthCheck(); }
+ bool visitSelection(Visit, TIntermSelection *) override { return depthCheck(); }
+ bool visitAggregate(Visit, TIntermAggregate *) override { return depthCheck(); }
+ bool visitLoop(Visit, TIntermLoop *) override { return depthCheck(); }
+ bool visitBranch(Visit, TIntermBranch *) override { return depthCheck(); }
protected:
bool depthCheck() const { return mMaxDepth < mDepthLimit; }
diff --git a/src/3rdparty/angle/src/compiler/translator/IntermTraverse.cpp b/src/3rdparty/angle/src/compiler/translator/IntermTraverse.cpp
index 7a7efb71f5..7b588ca5a3 100644
--- a/src/3rdparty/angle/src/compiler/translator/IntermTraverse.cpp
+++ b/src/3rdparty/angle/src/compiler/translator/IntermTraverse.cpp
@@ -5,6 +5,187 @@
//
#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/InfoSink.h"
+#include "compiler/translator/SymbolTable.h"
+
+void TIntermSymbol::traverse(TIntermTraverser *it)
+{
+ it->traverseSymbol(this);
+}
+
+void TIntermRaw::traverse(TIntermTraverser *it)
+{
+ it->traverseRaw(this);
+}
+
+void TIntermConstantUnion::traverse(TIntermTraverser *it)
+{
+ it->traverseConstantUnion(this);
+}
+
+void TIntermBinary::traverse(TIntermTraverser *it)
+{
+ it->traverseBinary(this);
+}
+
+void TIntermUnary::traverse(TIntermTraverser *it)
+{
+ it->traverseUnary(this);
+}
+
+void TIntermSelection::traverse(TIntermTraverser *it)
+{
+ it->traverseSelection(this);
+}
+
+void TIntermSwitch::traverse(TIntermTraverser *it)
+{
+ it->traverseSwitch(this);
+}
+
+void TIntermCase::traverse(TIntermTraverser *it)
+{
+ it->traverseCase(this);
+}
+
+void TIntermAggregate::traverse(TIntermTraverser *it)
+{
+ it->traverseAggregate(this);
+}
+
+void TIntermLoop::traverse(TIntermTraverser *it)
+{
+ it->traverseLoop(this);
+}
+
+void TIntermBranch::traverse(TIntermTraverser *it)
+{
+ it->traverseBranch(this);
+}
+
+void TIntermTraverser::pushParentBlock(TIntermAggregate *node)
+{
+ mParentBlockStack.push_back(ParentBlock(node, 0));
+}
+
+void TIntermTraverser::incrementParentBlockPos()
+{
+ ++mParentBlockStack.back().pos;
+}
+
+void TIntermTraverser::popParentBlock()
+{
+ ASSERT(!mParentBlockStack.empty());
+ mParentBlockStack.pop_back();
+}
+
+void TIntermTraverser::insertStatementsInParentBlock(const TIntermSequence &insertions)
+{
+ TIntermSequence emptyInsertionsAfter;
+ insertStatementsInParentBlock(insertions, emptyInsertionsAfter);
+}
+
+void TIntermTraverser::insertStatementsInParentBlock(const TIntermSequence &insertionsBefore,
+ const TIntermSequence &insertionsAfter)
+{
+ ASSERT(!mParentBlockStack.empty());
+ NodeInsertMultipleEntry insert(mParentBlockStack.back().node, mParentBlockStack.back().pos,
+ insertionsBefore, insertionsAfter);
+ mInsertions.push_back(insert);
+}
+
+TIntermSymbol *TIntermTraverser::createTempSymbol(const TType &type, TQualifier qualifier)
+{
+ // Each traversal uses at most one temporary variable, so the index stays the same within a single traversal.
+ TInfoSinkBase symbolNameOut;
+ ASSERT(mTemporaryIndex != nullptr);
+ symbolNameOut << "s" << (*mTemporaryIndex);
+ TString symbolName = symbolNameOut.c_str();
+
+ TIntermSymbol *node = new TIntermSymbol(0, symbolName, type);
+ node->setInternal(true);
+ node->getTypePointer()->setQualifier(qualifier);
+ return node;
+}
+
+TIntermSymbol *TIntermTraverser::createTempSymbol(const TType &type)
+{
+ return createTempSymbol(type, EvqTemporary);
+}
+
+TIntermAggregate *TIntermTraverser::createTempDeclaration(const TType &type)
+{
+ TIntermAggregate *tempDeclaration = new TIntermAggregate(EOpDeclaration);
+ tempDeclaration->getSequence()->push_back(createTempSymbol(type));
+ return tempDeclaration;
+}
+
+TIntermAggregate *TIntermTraverser::createTempInitDeclaration(TIntermTyped *initializer, TQualifier qualifier)
+{
+ ASSERT(initializer != nullptr);
+ TIntermSymbol *tempSymbol = createTempSymbol(initializer->getType(), qualifier);
+ TIntermAggregate *tempDeclaration = new TIntermAggregate(EOpDeclaration);
+ TIntermBinary *tempInit = new TIntermBinary(EOpInitialize);
+ tempInit->setLeft(tempSymbol);
+ tempInit->setRight(initializer);
+ tempInit->setType(tempSymbol->getType());
+ tempDeclaration->getSequence()->push_back(tempInit);
+ return tempDeclaration;
+}
+
+TIntermAggregate *TIntermTraverser::createTempInitDeclaration(TIntermTyped *initializer)
+{
+ return createTempInitDeclaration(initializer, EvqTemporary);
+}
+
+TIntermBinary *TIntermTraverser::createTempAssignment(TIntermTyped *rightNode)
+{
+ ASSERT(rightNode != nullptr);
+ TIntermSymbol *tempSymbol = createTempSymbol(rightNode->getType());
+ TIntermBinary *assignment = new TIntermBinary(EOpAssign);
+ assignment->setLeft(tempSymbol);
+ assignment->setRight(rightNode);
+ assignment->setType(tempSymbol->getType());
+ return assignment;
+}
+
+void TIntermTraverser::useTemporaryIndex(unsigned int *temporaryIndex)
+{
+ mTemporaryIndex = temporaryIndex;
+}
+
+void TIntermTraverser::nextTemporaryIndex()
+{
+ ASSERT(mTemporaryIndex != nullptr);
+ ++(*mTemporaryIndex);
+}
+
+void TLValueTrackingTraverser::addToFunctionMap(const TName &name, TIntermSequence *paramSequence)
+{
+ mFunctionMap[name] = paramSequence;
+}
+
+bool TLValueTrackingTraverser::isInFunctionMap(const TIntermAggregate *callNode) const
+{
+ ASSERT(callNode->getOp() == EOpFunctionCall);
+ return (mFunctionMap.find(callNode->getNameObj()) != mFunctionMap.end());
+}
+
+TIntermSequence *TLValueTrackingTraverser::getFunctionParameters(const TIntermAggregate *callNode)
+{
+ ASSERT(isInFunctionMap(callNode));
+ return mFunctionMap[callNode->getNameObj()];
+}
+
+void TLValueTrackingTraverser::setInFunctionCallOutParameter(bool inOutParameter)
+{
+ mInFunctionCallOutParameter = inOutParameter;
+}
+
+bool TLValueTrackingTraverser::isInFunctionCallOutParameter() const
+{
+ return mInFunctionCallOutParameter;
+}
//
// Traverse the intermediate representation tree, and
@@ -16,308 +197,473 @@
// if preVisit is turned on and the type specific function
// returns false.
//
-// preVisit, postVisit, and rightToLeft control what order
-// nodes are visited in.
-//
//
// Traversal functions for terminals are straighforward....
//
-void TIntermSymbol::traverse(TIntermTraverser *it)
+void TIntermTraverser::traverseSymbol(TIntermSymbol *node)
{
- it->visitSymbol(this);
+ visitSymbol(node);
}
-void TIntermConstantUnion::traverse(TIntermTraverser *it)
+void TIntermTraverser::traverseConstantUnion(TIntermConstantUnion *node)
{
- it->visitConstantUnion(this);
+ visitConstantUnion(node);
}
//
// Traverse a binary node.
//
-void TIntermBinary::traverse(TIntermTraverser *it)
+void TIntermTraverser::traverseBinary(TIntermBinary *node)
{
bool visit = true;
//
// visit the node before children if pre-visiting.
//
- if (it->preVisit)
- visit = it->visitBinary(PreVisit, this);
+ if (preVisit)
+ visit = visitBinary(PreVisit, node);
//
// Visit the children, in the right order.
//
if (visit)
{
- it->incrementDepth(this);
+ incrementDepth(node);
- if (it->rightToLeft)
- {
- if (mRight)
- mRight->traverse(it);
+ if (node->getLeft())
+ node->getLeft()->traverse(this);
- if (it->inVisit)
- visit = it->visitBinary(InVisit, this);
+ if (inVisit)
+ visit = visitBinary(InVisit, node);
- if (visit && mLeft)
- mLeft->traverse(it);
- }
- else
+ if (visit && node->getRight())
+ node->getRight()->traverse(this);
+
+ decrementDepth();
+ }
+
+ //
+ // Visit the node after the children, if requested and the traversal
+ // hasn't been cancelled yet.
+ //
+ if (visit && postVisit)
+ visitBinary(PostVisit, node);
+}
+
+void TLValueTrackingTraverser::traverseBinary(TIntermBinary *node)
+{
+ bool visit = true;
+
+ //
+ // visit the node before children if pre-visiting.
+ //
+ if (preVisit)
+ visit = visitBinary(PreVisit, node);
+
+ //
+ // Visit the children, in the right order.
+ //
+ if (visit)
+ {
+ incrementDepth(node);
+
+ // Some binary operations like indexing can be inside an expression which must be an
+ // l-value.
+ bool parentOperatorRequiresLValue = operatorRequiresLValue();
+ bool parentInFunctionCallOutParameter = isInFunctionCallOutParameter();
+ if (node->isAssignment())
{
- if (mLeft)
- mLeft->traverse(it);
+ ASSERT(!isLValueRequiredHere());
+ setOperatorRequiresLValue(true);
+ }
- if (it->inVisit)
- visit = it->visitBinary(InVisit, this);
+ if (node->getLeft())
+ node->getLeft()->traverse(this);
- if (visit && mRight)
- mRight->traverse(it);
+ if (inVisit)
+ visit = visitBinary(InVisit, node);
+
+ if (node->isAssignment())
+ setOperatorRequiresLValue(false);
+
+ // Index is not required to be an l-value even when the surrounding expression is required
+ // to be an l-value.
+ TOperator op = node->getOp();
+ if (op == EOpIndexDirect || op == EOpIndexDirectInterfaceBlock ||
+ op == EOpIndexDirectStruct || op == EOpIndexIndirect)
+ {
+ setOperatorRequiresLValue(false);
+ setInFunctionCallOutParameter(false);
}
- it->decrementDepth();
+ if (visit && node->getRight())
+ node->getRight()->traverse(this);
+
+ setOperatorRequiresLValue(parentOperatorRequiresLValue);
+ setInFunctionCallOutParameter(parentInFunctionCallOutParameter);
+
+ decrementDepth();
}
//
// Visit the node after the children, if requested and the traversal
// hasn't been cancelled yet.
//
- if (visit && it->postVisit)
- it->visitBinary(PostVisit, this);
+ if (visit && postVisit)
+ visitBinary(PostVisit, node);
}
//
// Traverse a unary node. Same comments in binary node apply here.
//
-void TIntermUnary::traverse(TIntermTraverser *it)
+void TIntermTraverser::traverseUnary(TIntermUnary *node)
{
bool visit = true;
- if (it->preVisit)
- visit = it->visitUnary(PreVisit, this);
+ if (preVisit)
+ visit = visitUnary(PreVisit, node);
+
+ if (visit)
+ {
+ incrementDepth(node);
- if (visit) {
- it->incrementDepth(this);
- mOperand->traverse(it);
- it->decrementDepth();
+ node->getOperand()->traverse(this);
+
+ decrementDepth();
}
- if (visit && it->postVisit)
- it->visitUnary(PostVisit, this);
+ if (visit && postVisit)
+ visitUnary(PostVisit, node);
+}
+
+void TLValueTrackingTraverser::traverseUnary(TIntermUnary *node)
+{
+ bool visit = true;
+
+ if (preVisit)
+ visit = visitUnary(PreVisit, node);
+
+ if (visit)
+ {
+ incrementDepth(node);
+
+ ASSERT(!operatorRequiresLValue());
+ switch (node->getOp())
+ {
+ case EOpPostIncrement:
+ case EOpPostDecrement:
+ case EOpPreIncrement:
+ case EOpPreDecrement:
+ setOperatorRequiresLValue(true);
+ break;
+ default:
+ break;
+ }
+
+ node->getOperand()->traverse(this);
+
+ setOperatorRequiresLValue(false);
+
+ decrementDepth();
+ }
+
+ if (visit && postVisit)
+ visitUnary(PostVisit, node);
}
//
// Traverse an aggregate node. Same comments in binary node apply here.
//
-void TIntermAggregate::traverse(TIntermTraverser *it)
+void TIntermTraverser::traverseAggregate(TIntermAggregate *node)
{
bool visit = true;
- if (it->preVisit)
- visit = it->visitAggregate(PreVisit, this);
+ TIntermSequence *sequence = node->getSequence();
+
+ if (preVisit)
+ visit = visitAggregate(PreVisit, node);
if (visit)
{
- it->incrementDepth(this);
+ incrementDepth(node);
- if (it->rightToLeft)
+ if (node->getOp() == EOpSequence)
+ pushParentBlock(node);
+
+ for (auto *child : *sequence)
{
- for (TIntermSequence::reverse_iterator sit = mSequence.rbegin();
- sit != mSequence.rend(); sit++)
+ child->traverse(this);
+ if (visit && inVisit)
{
- (*sit)->traverse(it);
+ if (child != sequence->back())
+ visit = visitAggregate(InVisit, node);
+ }
+
+ if (node->getOp() == EOpSequence)
+ incrementParentBlockPos();
+ }
+
+ if (node->getOp() == EOpSequence)
+ popParentBlock();
+
+ decrementDepth();
+ }
- if (visit && it->inVisit)
+ if (visit && postVisit)
+ visitAggregate(PostVisit, node);
+}
+
+void TLValueTrackingTraverser::traverseAggregate(TIntermAggregate *node)
+{
+ bool visit = true;
+
+ TIntermSequence *sequence = node->getSequence();
+ switch (node->getOp())
+ {
+ case EOpFunction:
+ {
+ TIntermAggregate *params = sequence->front()->getAsAggregate();
+ ASSERT(params != nullptr);
+ ASSERT(params->getOp() == EOpParameters);
+ addToFunctionMap(node->getNameObj(), params->getSequence());
+ break;
+ }
+ case EOpPrototype:
+ addToFunctionMap(node->getNameObj(), sequence);
+ break;
+ default:
+ break;
+ }
+
+ if (preVisit)
+ visit = visitAggregate(PreVisit, node);
+
+ if (visit)
+ {
+ bool inFunctionMap = false;
+ if (node->getOp() == EOpFunctionCall)
+ {
+ inFunctionMap = isInFunctionMap(node);
+ if (!inFunctionMap)
+ {
+ // The function is not user-defined - it is likely built-in texture function.
+ // Assume that those do not have out parameters.
+ setInFunctionCallOutParameter(false);
+ }
+ }
+
+ incrementDepth(node);
+
+ if (inFunctionMap)
+ {
+ TIntermSequence *params = getFunctionParameters(node);
+ TIntermSequence::iterator paramIter = params->begin();
+ for (auto *child : *sequence)
+ {
+ ASSERT(paramIter != params->end());
+ TQualifier qualifier = (*paramIter)->getAsTyped()->getQualifier();
+ setInFunctionCallOutParameter(qualifier == EvqOut || qualifier == EvqInOut);
+
+ child->traverse(this);
+ if (visit && inVisit)
{
- if (*sit != mSequence.front())
- visit = it->visitAggregate(InVisit, this);
+ if (child != sequence->back())
+ visit = visitAggregate(InVisit, node);
}
+
+ ++paramIter;
}
+
+ setInFunctionCallOutParameter(false);
}
else
{
- for (TIntermSequence::iterator sit = mSequence.begin();
- sit != mSequence.end(); sit++)
+ if (node->getOp() == EOpSequence)
+ pushParentBlock(node);
+
+ // Find the built-in function corresponding to this op so that we can determine the
+ // in/out qualifiers of its parameters.
+ TFunction *builtInFunc = nullptr;
+ TString opString = GetOperatorString(node->getOp());
+ if (!node->isConstructor() && !opString.empty())
+ {
+ // The return type doesn't affect the mangled name of the function, which is used
+ // to look it up from the symbol table.
+ TType dummyReturnType;
+ TFunction call(&opString, &dummyReturnType, node->getOp());
+ for (auto *child : *sequence)
+ {
+ TType *paramType = child->getAsTyped()->getTypePointer();
+ TConstParameter p(paramType);
+ call.addParameter(p);
+ }
+
+ TSymbol *sym = mSymbolTable.findBuiltIn(call.getMangledName(), mShaderVersion);
+ if (sym != nullptr && sym->isFunction())
+ {
+ builtInFunc = static_cast<TFunction *>(sym);
+ ASSERT(builtInFunc->getParamCount() == sequence->size());
+ }
+ }
+
+ size_t paramIndex = 0;
+
+ for (auto *child : *sequence)
{
- (*sit)->traverse(it);
+ TQualifier qualifier = EvqIn;
+ if (builtInFunc != nullptr)
+ qualifier = builtInFunc->getParam(paramIndex).type->getQualifier();
+ setInFunctionCallOutParameter(qualifier == EvqOut || qualifier == EvqInOut);
+ child->traverse(this);
- if (visit && it->inVisit)
+ if (visit && inVisit)
{
- if (*sit != mSequence.back())
- visit = it->visitAggregate(InVisit, this);
+ if (child != sequence->back())
+ visit = visitAggregate(InVisit, node);
}
+
+ if (node->getOp() == EOpSequence)
+ incrementParentBlockPos();
+
+ ++paramIndex;
}
+
+ setInFunctionCallOutParameter(false);
+
+ if (node->getOp() == EOpSequence)
+ popParentBlock();
}
- it->decrementDepth();
+ decrementDepth();
}
- if (visit && it->postVisit)
- it->visitAggregate(PostVisit, this);
+ if (visit && postVisit)
+ visitAggregate(PostVisit, node);
}
//
// Traverse a selection node. Same comments in binary node apply here.
//
-void TIntermSelection::traverse(TIntermTraverser *it)
+void TIntermTraverser::traverseSelection(TIntermSelection *node)
{
bool visit = true;
- if (it->preVisit)
- visit = it->visitSelection(PreVisit, this);
+ if (preVisit)
+ visit = visitSelection(PreVisit, node);
if (visit)
{
- it->incrementDepth(this);
- if (it->rightToLeft)
- {
- if (mFalseBlock)
- mFalseBlock->traverse(it);
- if (mTrueBlock)
- mTrueBlock->traverse(it);
- mCondition->traverse(it);
- }
- else
- {
- mCondition->traverse(it);
- if (mTrueBlock)
- mTrueBlock->traverse(it);
- if (mFalseBlock)
- mFalseBlock->traverse(it);
- }
- it->decrementDepth();
+ incrementDepth(node);
+ node->getCondition()->traverse(this);
+ if (node->getTrueBlock())
+ node->getTrueBlock()->traverse(this);
+ if (node->getFalseBlock())
+ node->getFalseBlock()->traverse(this);
+ decrementDepth();
}
- if (visit && it->postVisit)
- it->visitSelection(PostVisit, this);
+ if (visit && postVisit)
+ visitSelection(PostVisit, node);
}
//
// Traverse a switch node. Same comments in binary node apply here.
//
-void TIntermSwitch::traverse(TIntermTraverser *it)
+void TIntermTraverser::traverseSwitch(TIntermSwitch *node)
{
bool visit = true;
- if (it->preVisit)
- visit = it->visitSwitch(PreVisit, this);
+ if (preVisit)
+ visit = visitSwitch(PreVisit, node);
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();
+ incrementDepth(node);
+ node->getInit()->traverse(this);
+ if (inVisit)
+ visit = visitSwitch(InVisit, node);
+ if (visit && node->getStatementList())
+ node->getStatementList()->traverse(this);
+ decrementDepth();
}
- if (visit && it->postVisit)
- it->visitSwitch(PostVisit, this);
+ if (visit && postVisit)
+ visitSwitch(PostVisit, node);
}
//
-// Traverse a switch node. Same comments in binary node apply here.
+// Traverse a case node. Same comments in binary node apply here.
//
-void TIntermCase::traverse(TIntermTraverser *it)
+void TIntermTraverser::traverseCase(TIntermCase *node)
{
bool visit = true;
- if (it->preVisit)
- visit = it->visitCase(PreVisit, this);
+ if (preVisit)
+ visit = visitCase(PreVisit, node);
- if (visit && mCondition)
- mCondition->traverse(it);
+ if (visit && node->getCondition())
+ node->getCondition()->traverse(this);
- if (visit && it->postVisit)
- it->visitCase(PostVisit, this);
+ if (visit && postVisit)
+ visitCase(PostVisit, node);
}
//
// Traverse a loop node. Same comments in binary node apply here.
//
-void TIntermLoop::traverse(TIntermTraverser *it)
+void TIntermTraverser::traverseLoop(TIntermLoop *node)
{
bool visit = true;
- if (it->preVisit)
- visit = it->visitLoop(PreVisit, this);
+ if (preVisit)
+ visit = visitLoop(PreVisit, node);
if (visit)
{
- it->incrementDepth(this);
-
- if (it->rightToLeft)
- {
- if (mExpr)
- mExpr->traverse(it);
-
- if (mBody)
- mBody->traverse(it);
-
- if (mCond)
- mCond->traverse(it);
+ incrementDepth(node);
- if (mInit)
- mInit->traverse(it);
- }
- else
- {
- if (mInit)
- mInit->traverse(it);
+ if (node->getInit())
+ node->getInit()->traverse(this);
- if (mCond)
- mCond->traverse(it);
+ if (node->getCondition())
+ node->getCondition()->traverse(this);
- if (mBody)
- mBody->traverse(it);
+ if (node->getBody())
+ node->getBody()->traverse(this);
- if (mExpr)
- mExpr->traverse(it);
- }
+ if (node->getExpression())
+ node->getExpression()->traverse(this);
- it->decrementDepth();
+ decrementDepth();
}
- if (visit && it->postVisit)
- it->visitLoop(PostVisit, this);
+ if (visit && postVisit)
+ visitLoop(PostVisit, node);
}
//
// Traverse a branch node. Same comments in binary node apply here.
//
-void TIntermBranch::traverse(TIntermTraverser *it)
+void TIntermTraverser::traverseBranch(TIntermBranch *node)
{
bool visit = true;
- if (it->preVisit)
- visit = it->visitBranch(PreVisit, this);
+ if (preVisit)
+ visit = visitBranch(PreVisit, node);
- if (visit && mExpression) {
- it->incrementDepth(this);
- mExpression->traverse(it);
- it->decrementDepth();
+ if (visit && node->getExpression())
+ {
+ incrementDepth(node);
+ node->getExpression()->traverse(this);
+ decrementDepth();
}
- if (visit && it->postVisit)
- it->visitBranch(PostVisit, this);
+ if (visit && postVisit)
+ visitBranch(PostVisit, node);
}
-void TIntermRaw::traverse(TIntermTraverser *it)
+void TIntermTraverser::traverseRaw(TIntermRaw *node)
{
- it->visitRaw(this);
+ visitRaw(node);
}
diff --git a/src/3rdparty/angle/src/compiler/translator/Intermediate.cpp b/src/3rdparty/angle/src/compiler/translator/Intermediate.cpp
index 320056f8ce..0adb7212b7 100644
--- a/src/3rdparty/angle/src/compiler/translator/Intermediate.cpp
+++ b/src/3rdparty/angle/src/compiler/translator/Intermediate.cpp
@@ -57,19 +57,10 @@ TIntermTyped *TIntermediate::addBinaryMath(
if (!node->promote(mInfoSink))
return NULL;
- //
// See if we can fold constants.
- //
- TIntermConstantUnion *leftTempConstant = left->getAsConstantUnion();
- TIntermConstantUnion *rightTempConstant = right->getAsConstantUnion();
- if (leftTempConstant && rightTempConstant)
- {
- TIntermTyped *typedReturnNode =
- leftTempConstant->fold(node->getOp(), rightTempConstant, mInfoSink);
-
- if (typedReturnNode)
- return typedReturnNode;
- }
+ TIntermTyped *foldedNode = node->fold(mInfoSink);
+ if (foldedNode)
+ return foldedNode;
return node;
}
@@ -129,10 +120,6 @@ TIntermTyped *TIntermediate::addIndex(
TIntermTyped *TIntermediate::addUnaryMath(
TOperator op, TIntermTyped *child, const TSourceLoc &line, const TType *funcReturnType)
{
- TIntermConstantUnion *childTempConstant = 0;
- if (child->getAsConstantUnion())
- childTempConstant = child->getAsConstantUnion();
-
//
// Make a new node for the operator.
//
@@ -141,13 +128,9 @@ TIntermTyped *TIntermediate::addUnaryMath(
node->setOperand(child);
node->promote(funcReturnType);
- if (childTempConstant)
- {
- TIntermTyped *newChild = childTempConstant->fold(op, 0, mInfoSink);
-
- if (newChild)
- return newChild;
- }
+ TIntermTyped *foldedNode = node->fold(mInfoSink);
+ if (foldedNode)
+ return foldedNode;
return node;
}
@@ -246,6 +229,22 @@ TIntermAggregate *TIntermediate::makeAggregate(
return aggNode;
}
+// If the input node is nullptr, return nullptr.
+// If the input node is a sequence (block) node, return it.
+// If the input node is not a sequence node, put it inside a sequence node and return that.
+TIntermAggregate *TIntermediate::ensureSequence(TIntermNode *node)
+{
+ if (node == nullptr)
+ return nullptr;
+ TIntermAggregate *aggNode = node->getAsAggregate();
+ if (aggNode != nullptr && aggNode->getOp() == EOpSequence)
+ return aggNode;
+
+ aggNode = makeAggregate(node, node->getLine());
+ aggNode->setOp(EOpSequence);
+ return aggNode;
+}
+
//
// For "if" test nodes. There are three children; a condition,
// a true path, and a false path. The two paths are in the
@@ -261,7 +260,7 @@ TIntermNode *TIntermediate::addSelection(
// test now.
//
- if (cond->getAsTyped() && cond->getAsTyped()->getAsConstantUnion())
+ if (cond->getAsConstantUnion())
{
if (cond->getAsConstantUnion()->getBConst(0) == true)
{
@@ -276,28 +275,38 @@ TIntermNode *TIntermediate::addSelection(
}
TIntermSelection *node = new TIntermSelection(
- cond, nodePair.node1, nodePair.node2);
+ cond, ensureSequence(nodePair.node1), ensureSequence(nodePair.node2));
node->setLine(line);
return node;
}
-TIntermTyped *TIntermediate::addComma(
- TIntermTyped *left, TIntermTyped *right, const TSourceLoc &line)
+TIntermTyped *TIntermediate::addComma(TIntermTyped *left,
+ TIntermTyped *right,
+ const TSourceLoc &line,
+ int shaderVersion)
{
- if (left->getType().getQualifier() == EvqConst &&
- right->getType().getQualifier() == EvqConst)
+ TQualifier resultQualifier = EvqConst;
+ // ESSL3.00 section 12.43: The result of a sequence operator is not a constant-expression.
+ if (shaderVersion >= 300 || left->getQualifier() != EvqConst ||
+ right->getQualifier() != EvqConst)
{
- return right;
+ resultQualifier = EvqTemporary;
+ }
+
+ TIntermTyped *commaNode = nullptr;
+ if (!left->hasSideEffects())
+ {
+ commaNode = right;
}
else
{
- TIntermTyped *commaAggregate = growAggregate(left, right, line);
- commaAggregate->getAsAggregate()->setOp(EOpComma);
- commaAggregate->setType(right->getType());
- commaAggregate->getTypePointer()->setQualifier(EvqTemporary);
- return commaAggregate;
+ commaNode = growAggregate(left, right, line);
+ commaNode->getAsAggregate()->setOp(EOpComma);
+ commaNode->setType(right->getType());
}
+ commaNode->getTypePointer()->setQualifier(resultQualifier);
+ return commaNode;
}
//
@@ -305,38 +314,38 @@ TIntermTyped *TIntermediate::addComma(
// a true path, and a false path. The two paths are specified
// as separate parameters.
//
-// Returns the selection node created, or 0 if one could not be.
+// Returns the selection node created, or one of trueBlock and falseBlock if the expression could be folded.
//
-TIntermTyped *TIntermediate::addSelection(
- TIntermTyped *cond, TIntermTyped *trueBlock, TIntermTyped *falseBlock,
- const TSourceLoc &line)
+TIntermTyped *TIntermediate::addSelection(TIntermTyped *cond, TIntermTyped *trueBlock, TIntermTyped *falseBlock,
+ const TSourceLoc &line)
{
- if (!cond || !trueBlock || !falseBlock ||
- trueBlock->getType() != falseBlock->getType())
+ TQualifier resultQualifier = EvqTemporary;
+ if (cond->getQualifier() == EvqConst && trueBlock->getQualifier() == EvqConst &&
+ falseBlock->getQualifier() == EvqConst)
{
- return NULL;
+ resultQualifier = EvqConst;
}
-
- //
- // See if all the operands are constant, then fold it otherwise not.
- //
-
- if (cond->getAsConstantUnion() &&
- trueBlock->getAsConstantUnion() &&
- falseBlock->getAsConstantUnion())
+ // Note that the node resulting from here can be a constant union without being qualified as
+ // constant.
+ if (cond->getAsConstantUnion())
{
if (cond->getAsConstantUnion()->getBConst(0))
+ {
+ trueBlock->getTypePointer()->setQualifier(resultQualifier);
return trueBlock;
+ }
else
+ {
+ falseBlock->getTypePointer()->setQualifier(resultQualifier);
return falseBlock;
+ }
}
//
// Make a selection node.
//
- TIntermSelection *node = new TIntermSelection(
- cond, trueBlock, falseBlock, trueBlock->getType());
- node->getTypePointer()->setQualifier(EvqTemporary);
+ TIntermSelection *node = new TIntermSelection(cond, trueBlock, falseBlock, trueBlock->getType());
+ node->getTypePointer()->setQualifier(resultQualifier);
node->setLine(line);
return node;
@@ -366,10 +375,11 @@ TIntermCase *TIntermediate::addCase(
// Returns the constant union node created.
//
-TIntermConstantUnion *TIntermediate::addConstantUnion(
- ConstantUnion *unionArrayPointer, const TType &t, const TSourceLoc &line)
+TIntermConstantUnion *TIntermediate::addConstantUnion(const TConstantUnion *constantUnion,
+ const TType &type,
+ const TSourceLoc &line)
{
- TIntermConstantUnion *node = new TIntermConstantUnion(unionArrayPointer, t);
+ TIntermConstantUnion *node = new TIntermConstantUnion(constantUnion, type);
node->setLine(line);
return node;
@@ -384,11 +394,11 @@ TIntermTyped *TIntermediate::addSwizzle(
node->setLine(line);
TIntermConstantUnion *constIntNode;
TIntermSequence *sequenceVector = node->getSequence();
- ConstantUnion *unionArray;
+ TConstantUnion *unionArray;
for (int i = 0; i < fields.num; i++)
{
- unionArray = new ConstantUnion[1];
+ unionArray = new TConstantUnion[1];
unionArray->setIConst(fields.offsets[i]);
constIntNode = addConstantUnion(
unionArray, TType(EbtInt, EbpUndefined, EvqConst), line);
@@ -405,7 +415,7 @@ TIntermNode *TIntermediate::addLoop(
TLoopType type, TIntermNode *init, TIntermTyped *cond, TIntermTyped *expr,
TIntermNode *body, const TSourceLoc &line)
{
- TIntermNode *node = new TIntermLoop(type, init, cond, expr, body);
+ TIntermNode *node = new TIntermLoop(type, init, cond, expr, ensureSequence(body));
node->setLine(line);
return node;
@@ -433,17 +443,66 @@ TIntermBranch* TIntermediate::addBranch(
// This is to be executed once the final root is put on top by the parsing
// process.
//
-bool TIntermediate::postProcess(TIntermNode *root)
+TIntermAggregate *TIntermediate::postProcess(TIntermNode *root)
{
- if (root == NULL)
- return true;
+ if (root == nullptr)
+ return nullptr;
//
- // First, finish off the top level sequence, if any
+ // Finish off the top level sequence, if any
//
TIntermAggregate *aggRoot = root->getAsAggregate();
- if (aggRoot && aggRoot->getOp() == EOpNull)
+ if (aggRoot != nullptr && aggRoot->getOp() == EOpNull)
+ {
aggRoot->setOp(EOpSequence);
+ }
+ else if (aggRoot == nullptr || aggRoot->getOp() != EOpSequence)
+ {
+ aggRoot = new TIntermAggregate(EOpSequence);
+ aggRoot->setLine(root->getLine());
+ aggRoot->getSequence()->push_back(root);
+ }
+
+ return aggRoot;
+}
+
+TIntermTyped *TIntermediate::foldAggregateBuiltIn(TIntermAggregate *aggregate)
+{
+ switch (aggregate->getOp())
+ {
+ case EOpAtan:
+ case EOpPow:
+ case EOpMod:
+ case EOpMin:
+ case EOpMax:
+ case EOpClamp:
+ case EOpMix:
+ case EOpStep:
+ case EOpSmoothStep:
+ case EOpMul:
+ case EOpOuterProduct:
+ case EOpLessThan:
+ case EOpLessThanEqual:
+ case EOpGreaterThan:
+ case EOpGreaterThanEqual:
+ case EOpVectorEqual:
+ case EOpVectorNotEqual:
+ case EOpDistance:
+ case EOpDot:
+ case EOpCross:
+ case EOpFaceForward:
+ case EOpReflect:
+ case EOpRefract:
+ return aggregate->fold(mInfoSink);
+ default:
+ // TODO: Add support for folding array constructors
+ if (aggregate->isConstructor() && !aggregate->isArray())
+ {
+ return aggregate->fold(mInfoSink);
+ }
+ // Constant folding not supported for the built-in.
+ return nullptr;
+ }
- return true;
+ return nullptr;
}
diff --git a/src/3rdparty/angle/src/compiler/translator/Intermediate.h b/src/3rdparty/angle/src/compiler/translator/Intermediate.h
index ec73e22834..f723fc7648 100644
--- a/src/3rdparty/angle/src/compiler/translator/Intermediate.h
+++ b/src/3rdparty/angle/src/compiler/translator/Intermediate.h
@@ -39,29 +39,33 @@ class TIntermediate
TIntermAggregate *growAggregate(
TIntermNode *left, TIntermNode *right, const TSourceLoc &);
TIntermAggregate *makeAggregate(TIntermNode *node, const TSourceLoc &);
+ TIntermAggregate *ensureSequence(TIntermNode *node);
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 *addSelection(TIntermTyped *cond, TIntermTyped *trueBlock, TIntermTyped *falseBlock,
+ const TSourceLoc &line);
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);
+ TIntermTyped *addComma(TIntermTyped *left,
+ TIntermTyped *right,
+ const TSourceLoc &line,
+ int shaderVersion);
+ TIntermConstantUnion *addConstantUnion(const TConstantUnion *constantUnion,
+ const TType &type,
+ const TSourceLoc &line);
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 *);
+ TIntermAggregate *postProcess(TIntermNode *root);
static void outputTree(TIntermNode *, TInfoSinkBase &);
+ TIntermTyped *foldAggregateBuiltIn(TIntermAggregate *aggregate);
+
private:
void operator=(TIntermediate &); // prevent assignments
diff --git a/src/3rdparty/angle/src/compiler/translator/NodeSearch.h b/src/3rdparty/angle/src/compiler/translator/NodeSearch.h
index 8ffed614c3..b13b1baabb 100644
--- a/src/3rdparty/angle/src/compiler/translator/NodeSearch.h
+++ b/src/3rdparty/angle/src/compiler/translator/NodeSearch.h
@@ -19,7 +19,8 @@ class NodeSearchTraverser : public TIntermTraverser
{
public:
NodeSearchTraverser()
- : mFound(false)
+ : TIntermTraverser(true, false, false),
+ mFound(false)
{}
bool found() const { return mFound; }
@@ -53,28 +54,6 @@ class FindDiscard : public NodeSearchTraverser<FindDiscard>
}
};
-class FindSideEffectRewriting : public NodeSearchTraverser<FindSideEffectRewriting>
-{
- public:
- virtual bool visitBinary(Visit visit, TIntermBinary *node)
- {
- switch (node->getOp())
- {
- case EOpLogicalOr:
- case EOpLogicalAnd:
- if (node->getRight()->hasSideEffects())
- {
- mFound = true;
- }
- break;
-
- default: break;
- }
-
- return !mFound;
- }
-};
-
}
#endif // COMPILER_TRANSLATOR_NODESEARCH_H_
diff --git a/src/3rdparty/angle/src/compiler/translator/Operator.cpp b/src/3rdparty/angle/src/compiler/translator/Operator.cpp
index ae4512bd44..20e47f290e 100644
--- a/src/3rdparty/angle/src/compiler/translator/Operator.cpp
+++ b/src/3rdparty/angle/src/compiler/translator/Operator.cpp
@@ -164,7 +164,13 @@ const char *GetOperatorString(TOperator op)
case EOpConstructUVec3: return "uvec3";
case EOpConstructUVec4: return "uvec4";
case EOpConstructMat2: return "mat2";
+ case EOpConstructMat2x3: return "mat2x3";
+ case EOpConstructMat2x4: return "mat2x4";
+ case EOpConstructMat3x2: return "mat3x2";
case EOpConstructMat3: return "mat3";
+ case EOpConstructMat3x4: return "mat3x4";
+ case EOpConstructMat4x2: return "mat4x2";
+ case EOpConstructMat4x3: return "mat4x3";
case EOpConstructMat4: return "mat4";
// Note: EOpConstructStruct can't be handled here
diff --git a/src/3rdparty/angle/src/compiler/translator/Operator.h b/src/3rdparty/angle/src/compiler/translator/Operator.h
index 8290f952fc..b0efb8f48b 100644
--- a/src/3rdparty/angle/src/compiler/translator/Operator.h
+++ b/src/3rdparty/angle/src/compiler/translator/Operator.h
@@ -15,7 +15,6 @@ 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
@@ -192,7 +191,13 @@ enum TOperator
EOpConstructUVec3,
EOpConstructUVec4,
EOpConstructMat2,
+ EOpConstructMat2x3,
+ EOpConstructMat2x4,
+ EOpConstructMat3x2,
EOpConstructMat3,
+ EOpConstructMat3x4,
+ EOpConstructMat4x2,
+ EOpConstructMat4x3,
EOpConstructMat4,
EOpConstructStruct,
diff --git a/src/3rdparty/angle/src/compiler/translator/OutputESSL.h b/src/3rdparty/angle/src/compiler/translator/OutputESSL.h
index 813f1e944b..c5a963499e 100644
--- a/src/3rdparty/angle/src/compiler/translator/OutputESSL.h
+++ b/src/3rdparty/angle/src/compiler/translator/OutputESSL.h
@@ -21,7 +21,8 @@ public:
bool forceHighp);
protected:
- virtual bool writeVariablePrecision(TPrecision precision);
+ bool writeVariablePrecision(TPrecision precision) override;
+
private:
bool mForceHighp;
};
diff --git a/src/3rdparty/angle/src/compiler/translator/OutputGLSL.cpp b/src/3rdparty/angle/src/compiler/translator/OutputGLSL.cpp
index 9badf0e2fc..431425020a 100644
--- a/src/3rdparty/angle/src/compiler/translator/OutputGLSL.cpp
+++ b/src/3rdparty/angle/src/compiler/translator/OutputGLSL.cpp
@@ -37,14 +37,22 @@ void TOutputGLSL::visitSymbol(TIntermSymbol *node)
{
out << "gl_FragDepth";
}
- else if (symbol == "gl_FragColor" && getShaderOutput() == SH_GLSL_CORE_OUTPUT)
+ else if (symbol == "gl_FragColor" && IsGLSL130OrNewer(getShaderOutput()))
{
out << "webgl_FragColor";
}
- else if (symbol == "gl_FragData" && getShaderOutput() == SH_GLSL_CORE_OUTPUT)
+ else if (symbol == "gl_FragData" && IsGLSL130OrNewer(getShaderOutput()))
{
out << "webgl_FragData";
}
+ else if (symbol == "gl_SecondaryFragColorEXT")
+ {
+ out << "angle_SecondaryFragColor";
+ }
+ else if (symbol == "gl_SecondaryFragDataEXT")
+ {
+ out << "angle_SecondaryFragData";
+ }
else
{
TOutputGLSLBase::visitSymbol(node);
@@ -67,6 +75,7 @@ TString TOutputGLSL::translateTextureFunction(TString &name)
"texture2DProj", "textureProj",
"texture2DLod", "textureLod",
"texture2DProjLod", "textureProjLod",
+ "texture2DRect", "texture",
"textureCube", "texture",
"textureCubeLod", "textureLod",
// Extensions
@@ -78,7 +87,7 @@ TString TOutputGLSL::translateTextureFunction(TString &name)
"textureCubeGradEXT", "textureGrad",
NULL, NULL
};
- const char **mapping = (getShaderOutput() == SH_GLSL_CORE_OUTPUT) ?
+ const char **mapping = (IsGLSL130OrNewer(getShaderOutput())) ?
legacyToCoreRename : simpleRename;
for (int i = 0; mapping[i] != NULL; i += 2)
diff --git a/src/3rdparty/angle/src/compiler/translator/OutputGLSL.h b/src/3rdparty/angle/src/compiler/translator/OutputGLSL.h
index 21b2d079d3..9b1aca4eab 100644
--- a/src/3rdparty/angle/src/compiler/translator/OutputGLSL.h
+++ b/src/3rdparty/angle/src/compiler/translator/OutputGLSL.h
@@ -21,9 +21,9 @@ class TOutputGLSL : public TOutputGLSLBase
ShShaderOutput output);
protected:
- virtual bool writeVariablePrecision(TPrecision);
- virtual void visitSymbol(TIntermSymbol* node);
- virtual TString translateTextureFunction(TString& name);
+ bool writeVariablePrecision(TPrecision) override;
+ void visitSymbol(TIntermSymbol *node) override;
+ TString translateTextureFunction(TString &name) override;
};
#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 4bb6305d05..f048b050b7 100644
--- a/src/3rdparty/angle/src/compiler/translator/OutputGLSLBase.cpp
+++ b/src/3rdparty/angle/src/compiler/translator/OutputGLSLBase.cpp
@@ -5,7 +5,8 @@
//
#include "compiler/translator/OutputGLSLBase.h"
-#include "compiler/translator/compilerdebug.h"
+
+#include "common/debug.h"
#include <cfloat>
@@ -88,30 +89,46 @@ void TOutputGLSLBase::writeBuiltInFunctionTriplet(
writeTriplet(visit, preString.c_str(), ", ", ")");
}
+void TOutputGLSLBase::writeLayoutQualifier(const TType &type)
+{
+ if (type.getQualifier() == EvqFragmentOut || type.getQualifier() == EvqVertexIn)
+ {
+ const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier();
+ if (layoutQualifier.location >= 0)
+ {
+ TInfoSinkBase &out = objSink();
+ out << "layout(location = " << layoutQualifier.location << ") ";
+ }
+ }
+}
+
void TOutputGLSLBase::writeVariableType(const TType &type)
{
TInfoSinkBase &out = objSink();
+ if (type.isInvariant())
+ {
+ out << "invariant ";
+ }
+ if (type.getBasicType() == EbtInterfaceBlock)
+ {
+ TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
+ declareInterfaceBlockLayout(interfaceBlock);
+ }
TQualifier qualifier = type.getQualifier();
if (qualifier != EvqTemporary && qualifier != EvqGlobal)
{
- if (mOutput == SH_GLSL_CORE_OUTPUT)
+ if (IsGLSL130OrNewer(mOutput))
{
switch (qualifier)
{
case EvqAttribute:
- out << "in" << " ";
+ out << "in ";
break;
case EvqVaryingIn:
- out << "in" << " ";
+ out << "in ";
break;
case EvqVaryingOut:
- out << "out" << " ";
- break;
- case EvqInvariantVaryingIn:
- out << "invariant in" << " ";
- break;
- case EvqInvariantVaryingOut:
- out << "invariant out" << " ";
+ out << "out ";
break;
default:
out << type.getQualifierString() << " ";
@@ -135,6 +152,11 @@ void TOutputGLSLBase::writeVariableType(const TType &type)
mDeclaredStructs.insert(structure->uniqueId());
}
}
+ else if (type.getBasicType() == EbtInterfaceBlock)
+ {
+ TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
+ declareInterfaceBlock(interfaceBlock);
+ }
else
{
if (writeVariablePrecision(type.getPrecision()))
@@ -167,8 +189,8 @@ void TOutputGLSLBase::writeFunctionParameters(const TIntermSequence &args)
}
}
-const ConstantUnion *TOutputGLSLBase::writeConstantUnion(
- const TType &type, const ConstantUnion *pConstUnion)
+const TConstantUnion *TOutputGLSLBase::writeConstantUnion(
+ const TType &type, const TConstantUnion *pConstUnion)
{
TInfoSinkBase &out = objSink();
@@ -221,6 +243,28 @@ const ConstantUnion *TOutputGLSLBase::writeConstantUnion(
return pConstUnion;
}
+void TOutputGLSLBase::writeConstructorTriplet(Visit visit, const TType &type, const char *constructorBaseType)
+{
+ TInfoSinkBase &out = objSink();
+ if (visit == PreVisit)
+ {
+ if (type.isArray())
+ {
+ out << constructorBaseType;
+ out << arrayBrackets(type);
+ out << "(";
+ }
+ else
+ {
+ out << constructorBaseType << "(";
+ }
+ }
+ else
+ {
+ writeTriplet(visit, nullptr, ", ", ")");
+ }
+}
+
void TOutputGLSLBase::visitSymbol(TIntermSymbol *node)
{
TInfoSinkBase &out = objSink();
@@ -352,6 +396,22 @@ bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary *node)
visitChildren = false;
}
break;
+ case EOpIndexDirectInterfaceBlock:
+ if (visit == InVisit)
+ {
+ out << ".";
+ const TInterfaceBlock *interfaceBlock = node->getLeft()->getType().getInterfaceBlock();
+ const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
+ const TField *field = interfaceBlock->fields()[index->getIConst(0)];
+
+ TString fieldName = field->name();
+ ASSERT(!mSymbolTable.findBuiltIn(interfaceBlock->name(), mShaderVersion));
+ fieldName = hashName(fieldName);
+
+ out << fieldName;
+ visitChildren = false;
+ }
+ break;
case EOpVectorSwizzle:
if (visit == InVisit)
{
@@ -363,7 +423,7 @@ bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary *node)
TIntermConstantUnion *element = (*sit)->getAsConstantUnion();
ASSERT(element->getBasicType() == EbtInt);
ASSERT(element->getNominalSize() == 1);
- const ConstantUnion& data = element->getUnionArrayPointer()[0];
+ const TConstantUnion& data = element->getUnionArrayPointer()[0];
ASSERT(data.getType() == EbtInt);
switch (data.getIConst())
{
@@ -722,7 +782,6 @@ bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node)
{
bool visitChildren = true;
TInfoSinkBase &out = objSink();
- TString preString;
bool useEmulatedFunction = (visit == PreVisit && node->getUseEmulatedFunction());
switch (node->getOp())
{
@@ -756,8 +815,14 @@ bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node)
case EOpPrototype:
// Function declaration.
ASSERT(visit == PreVisit);
- writeVariableType(node->getType());
- out << " " << hashFunctionName(node->getName());
+ {
+ const TType &type = node->getType();
+ writeVariableType(type);
+ if (type.isArray())
+ out << arrayBrackets(type);
+ }
+
+ out << " " << hashFunctionNameIfNeeded(node->getNameObj());
out << "(";
writeFunctionParameters(*(node->getSequence()));
@@ -768,8 +833,14 @@ bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node)
case EOpFunction: {
// Function definition.
ASSERT(visit == PreVisit);
- writeVariableType(node->getType());
- out << " " << hashFunctionName(node->getName());
+ {
+ const TType &type = node->getType();
+ writeVariableType(type);
+ if (type.isArray())
+ out << arrayBrackets(type);
+ }
+
+ out << " " << hashFunctionNameIfNeeded(node->getNameObj());
incrementDepth(node);
// Function definition node contains one or two children nodes
@@ -798,16 +869,7 @@ bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node)
case EOpFunctionCall:
// Function call.
if (visit == PreVisit)
- out << hashFunctionName(node->getName()) << "(";
- else if (visit == InVisit)
- out << ", ";
- else
- out << ")";
- break;
- case EOpInternalFunctionCall:
- // Function call to an internal helper function.
- if (visit == PreVisit)
- out << node->getName() << "(";
+ out << hashFunctionNameIfNeeded(node->getNameObj()) << "(";
else if (visit == InVisit)
out << ", ";
else
@@ -827,6 +889,7 @@ bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node)
{
const TIntermSequence &sequence = *(node->getSequence());
const TIntermTyped *variable = sequence.front()->getAsTyped();
+ writeLayoutQualifier(variable->getType());
writeVariableType(variable->getType());
out << " ";
mDeclaringVariables = true;
@@ -854,66 +917,88 @@ bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node)
visitChildren = false;
break;
case EOpConstructFloat:
- writeTriplet(visit, "float(", NULL, ")");
+ writeConstructorTriplet(visit, node->getType(), "float");
break;
case EOpConstructVec2:
- writeBuiltInFunctionTriplet(visit, "vec2(", false);
+ writeConstructorTriplet(visit, node->getType(), "vec2");
break;
case EOpConstructVec3:
- writeBuiltInFunctionTriplet(visit, "vec3(", false);
+ writeConstructorTriplet(visit, node->getType(), "vec3");
break;
case EOpConstructVec4:
- writeBuiltInFunctionTriplet(visit, "vec4(", false);
+ writeConstructorTriplet(visit, node->getType(), "vec4");
break;
case EOpConstructBool:
- writeTriplet(visit, "bool(", NULL, ")");
+ writeConstructorTriplet(visit, node->getType(), "bool");
break;
case EOpConstructBVec2:
- writeBuiltInFunctionTriplet(visit, "bvec2(", false);
+ writeConstructorTriplet(visit, node->getType(), "bvec2");
break;
case EOpConstructBVec3:
- writeBuiltInFunctionTriplet(visit, "bvec3(", false);
+ writeConstructorTriplet(visit, node->getType(), "bvec3");
break;
case EOpConstructBVec4:
- writeBuiltInFunctionTriplet(visit, "bvec4(", false);
+ writeConstructorTriplet(visit, node->getType(), "bvec4");
break;
case EOpConstructInt:
- writeTriplet(visit, "int(", NULL, ")");
+ writeConstructorTriplet(visit, node->getType(), "int");
break;
case EOpConstructIVec2:
- writeBuiltInFunctionTriplet(visit, "ivec2(", false);
+ writeConstructorTriplet(visit, node->getType(), "ivec2");
break;
case EOpConstructIVec3:
- writeBuiltInFunctionTriplet(visit, "ivec3(", false);
+ writeConstructorTriplet(visit, node->getType(), "ivec3");
break;
case EOpConstructIVec4:
- writeBuiltInFunctionTriplet(visit, "ivec4(", false);
+ writeConstructorTriplet(visit, node->getType(), "ivec4");
+ break;
+ case EOpConstructUInt:
+ writeConstructorTriplet(visit, node->getType(), "uint");
+ break;
+ case EOpConstructUVec2:
+ writeConstructorTriplet(visit, node->getType(), "uvec2");
+ break;
+ case EOpConstructUVec3:
+ writeConstructorTriplet(visit, node->getType(), "uvec3");
+ break;
+ case EOpConstructUVec4:
+ writeConstructorTriplet(visit, node->getType(), "uvec4");
break;
case EOpConstructMat2:
- writeBuiltInFunctionTriplet(visit, "mat2(", false);
+ writeConstructorTriplet(visit, node->getType(), "mat2");
+ break;
+ case EOpConstructMat2x3:
+ writeConstructorTriplet(visit, node->getType(), "mat2x3");
+ break;
+ case EOpConstructMat2x4:
+ writeConstructorTriplet(visit, node->getType(), "mat2x4");
+ break;
+ case EOpConstructMat3x2:
+ writeConstructorTriplet(visit, node->getType(), "mat3x2");
break;
case EOpConstructMat3:
- writeBuiltInFunctionTriplet(visit, "mat3(", false);
+ writeConstructorTriplet(visit, node->getType(), "mat3");
+ break;
+ case EOpConstructMat3x4:
+ writeConstructorTriplet(visit, node->getType(), "mat3x4");
+ break;
+ case EOpConstructMat4x2:
+ writeConstructorTriplet(visit, node->getType(), "mat4x2");
+ break;
+ case EOpConstructMat4x3:
+ writeConstructorTriplet(visit, node->getType(), "mat4x3");
break;
case EOpConstructMat4:
- writeBuiltInFunctionTriplet(visit, "mat4(", false);
+ writeConstructorTriplet(visit, node->getType(), "mat4");
break;
case EOpConstructStruct:
- if (visit == PreVisit)
{
const TType &type = node->getType();
ASSERT(type.getBasicType() == EbtStruct);
- out << hashName(type.getStruct()->name()) << "(";
- }
- else if (visit == InVisit)
- {
- out << ", ";
- }
- else
- {
- out << ")";
+ TString constructorName = hashName(type.getStruct()->name());
+ writeConstructorTriplet(visit, node->getType(), constructorName.c_str());
+ break;
}
- break;
case EOpOuterProduct:
writeBuiltInFunctionTriplet(visit, "outerProduct(", useEmulatedFunction);
@@ -1004,8 +1089,12 @@ bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop *node)
TInfoSinkBase &out = objSink();
incrementDepth(node);
- // Loop header.
+
TLoopType loopType = node->getType();
+
+ // Only for loops can be unrolled
+ ASSERT(!node->getUnrollFlag() || loopType == ELoopFor);
+
if (loopType == ELoopFor) // for loop
{
if (!node->getUnrollFlag())
@@ -1022,6 +1111,8 @@ bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop *node)
if (node->getExpression())
node->getExpression()->traverse(this);
out << ")\n";
+
+ visitCodeBlock(node->getBody());
}
else
{
@@ -1034,6 +1125,16 @@ bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop *node)
out << "for (int " << name << " = 0; "
<< name << " < 1; "
<< "++" << name << ")\n";
+
+ out << "{\n";
+ mLoopUnrollStack.push(node);
+ while (mLoopUnrollStack.satisfiesLoopCondition())
+ {
+ visitCodeBlock(node->getBody());
+ mLoopUnrollStack.step();
+ }
+ mLoopUnrollStack.pop();
+ out << "}\n";
}
}
else if (loopType == ELoopWhile) // while loop
@@ -1042,39 +1143,22 @@ bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop *node)
ASSERT(node->getCondition() != NULL);
node->getCondition()->traverse(this);
out << ")\n";
+
+ visitCodeBlock(node->getBody());
}
else // do-while loop
{
ASSERT(loopType == ELoopDoWhile);
out << "do\n";
- }
- // Loop body.
- if (node->getUnrollFlag())
- {
- out << "{\n";
- mLoopUnrollStack.push(node);
- while (mLoopUnrollStack.satisfiesLoopCondition())
- {
- visitCodeBlock(node->getBody());
- mLoopUnrollStack.step();
- }
- mLoopUnrollStack.pop();
- out << "}\n";
- }
- else
- {
visitCodeBlock(node->getBody());
- }
- // Loop footer.
- if (loopType == ELoopDoWhile) // do-while loop
- {
out << "while (";
ASSERT(node->getCondition() != NULL);
node->getCondition()->traverse(this);
out << ");\n";
}
+
decrementDepth();
// No need to visit children. They have been already processed in
@@ -1129,6 +1213,10 @@ TString TOutputGLSLBase::getTypeName(const TType &type)
{
out << "mat";
out << type.getNominalSize();
+ if (type.getSecondarySize() != type.getNominalSize())
+ {
+ out << "x" << type.getSecondarySize();
+ }
}
else if (type.isVector())
{
@@ -1143,6 +1231,9 @@ TString TOutputGLSLBase::getTypeName(const TType &type)
case EbtBool:
out << "bvec";
break;
+ case EbtUInt:
+ out << "uvec";
+ break;
default:
UNREACHABLE();
}
@@ -1177,12 +1268,16 @@ TString TOutputGLSLBase::hashVariableName(const TString &name)
return hashName(name);
}
-TString TOutputGLSLBase::hashFunctionName(const TString &mangled_name)
+TString TOutputGLSLBase::hashFunctionNameIfNeeded(const TName &mangledName)
{
- TString name = TFunction::unmangleName(mangled_name);
- if (mSymbolTable.findBuiltIn(mangled_name, mShaderVersion) != NULL || name == "main")
+ TString mangledStr = mangledName.getString();
+ TString name = TFunction::unmangleName(mangledStr);
+ if (mSymbolTable.findBuiltIn(mangledStr, mShaderVersion) != nullptr || name == "main")
return translateTextureFunction(name);
- return hashName(name);
+ if (mangledName.isInternal())
+ return name;
+ else
+ return hashName(name);
}
bool TOutputGLSLBase::structDeclared(const TStructure *structure) const
@@ -1215,3 +1310,70 @@ void TOutputGLSLBase::declareStruct(const TStructure *structure)
out << "}";
}
+void TOutputGLSLBase::declareInterfaceBlockLayout(const TInterfaceBlock *interfaceBlock)
+{
+ TInfoSinkBase &out = objSink();
+
+ out << "layout(";
+
+ switch (interfaceBlock->blockStorage())
+ {
+ case EbsUnspecified:
+ case EbsShared:
+ // Default block storage is shared.
+ out << "shared";
+ break;
+
+ case EbsPacked:
+ out << "packed";
+ break;
+
+ case EbsStd140:
+ out << "std140";
+ break;
+
+ default:
+ UNREACHABLE();
+ break;
+ }
+
+ out << ", ";
+
+ switch (interfaceBlock->matrixPacking())
+ {
+ case EmpUnspecified:
+ case EmpColumnMajor:
+ // Default matrix packing is column major.
+ out << "column_major";
+ break;
+
+ case EmpRowMajor:
+ out << "row_major";
+ break;
+
+ default:
+ UNREACHABLE();
+ break;
+ }
+
+ out << ") ";
+}
+
+void TOutputGLSLBase::declareInterfaceBlock(const TInterfaceBlock *interfaceBlock)
+{
+ TInfoSinkBase &out = objSink();
+
+ out << hashName(interfaceBlock->name()) << "{\n";
+ const TFieldList &fields = interfaceBlock->fields();
+ for (size_t i = 0; i < fields.size(); ++i)
+ {
+ const TField *field = fields[i];
+ if (writeVariablePrecision(field->type()->getPrecision()))
+ out << " ";
+ out << getTypeName(*field->type()) << " " << hashName(field->name());
+ if (field->type()->isArray())
+ out << arrayBrackets(*field->type());
+ out << ";\n";
+ }
+ out << "}";
+}
diff --git a/src/3rdparty/angle/src/compiler/translator/OutputGLSLBase.h b/src/3rdparty/angle/src/compiler/translator/OutputGLSLBase.h
index 4e66059c21..2ae82d15b2 100644
--- a/src/3rdparty/angle/src/compiler/translator/OutputGLSLBase.h
+++ b/src/3rdparty/angle/src/compiler/translator/OutputGLSLBase.h
@@ -32,22 +32,24 @@ class TOutputGLSLBase : public TIntermTraverser
protected:
TInfoSinkBase &objSink() { return mObjSink; }
void writeTriplet(Visit visit, const char *preStr, const char *inStr, const char *postStr);
+ void writeLayoutQualifier(const TType &type);
void writeVariableType(const TType &type);
virtual bool writeVariablePrecision(TPrecision precision) = 0;
void writeFunctionParameters(const TIntermSequence &args);
- const ConstantUnion *writeConstantUnion(const TType &type, const ConstantUnion *pConstUnion);
+ const TConstantUnion *writeConstantUnion(const TType &type, const TConstantUnion *pConstUnion);
+ void writeConstructorTriplet(Visit visit, const TType &type, const char *constructorBaseType);
TString getTypeName(const TType &type);
- virtual void visitSymbol(TIntermSymbol *node);
- virtual void visitConstantUnion(TIntermConstantUnion *node);
- virtual bool visitBinary(Visit visit, TIntermBinary *node);
- virtual bool visitUnary(Visit visit, TIntermUnary *node);
- virtual bool visitSelection(Visit visit, TIntermSelection *node);
- virtual bool 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);
+ void visitSymbol(TIntermSymbol *node) override;
+ void visitConstantUnion(TIntermConstantUnion *node) override;
+ bool visitBinary(Visit visit, TIntermBinary *node) override;
+ bool visitUnary(Visit visit, TIntermUnary *node) override;
+ bool visitSelection(Visit visit, TIntermSelection *node) override;
+ bool visitSwitch(Visit visit, TIntermSwitch *node) override;
+ bool visitCase(Visit visit, TIntermCase *node) override;
+ bool visitAggregate(Visit visit, TIntermAggregate *node) override;
+ bool visitLoop(Visit visit, TIntermLoop *node) override;
+ bool visitBranch(Visit visit, TIntermBranch *node) override;
void visitCodeBlock(TIntermNode *node);
@@ -56,8 +58,8 @@ class TOutputGLSLBase : public TIntermTraverser
TString hashName(const TString &name);
// Same as hashName(), but without hashing built-in variables.
TString hashVariableName(const TString &name);
- // Same as hashName(), but without hashing built-in functions.
- TString hashFunctionName(const TString &mangled_name);
+ // Same as hashName(), but without hashing built-in functions and with unmangling.
+ TString hashFunctionNameIfNeeded(const TName &mangledName);
// Used to translate function names for differences between ESSL and GLSL
virtual TString translateTextureFunction(TString &name) { return name; }
@@ -65,6 +67,9 @@ class TOutputGLSLBase : public TIntermTraverser
bool structDeclared(const TStructure *structure) const;
void declareStruct(const TStructure *structure);
+ void declareInterfaceBlockLayout(const TInterfaceBlock *interfaceBlock);
+ void declareInterfaceBlock(const TInterfaceBlock *interfaceBlock);
+
void writeBuiltInFunctionTriplet(Visit visit, const char *preStr, bool useEmulatedFunction);
TInfoSinkBase &mObjSink;
diff --git a/src/3rdparty/angle/src/compiler/translator/OutputHLSL.cpp b/src/3rdparty/angle/src/compiler/translator/OutputHLSL.cpp
index 94225b81c4..253b96696c 100644
--- a/src/3rdparty/angle/src/compiler/translator/OutputHLSL.cpp
+++ b/src/3rdparty/angle/src/compiler/translator/OutputHLSL.cpp
@@ -11,45 +11,81 @@
#include <stdio.h>
#include "common/angleutils.h"
+#include "common/debug.h"
#include "common/utilities.h"
#include "compiler/translator/BuiltInFunctionEmulator.h"
#include "compiler/translator/BuiltInFunctionEmulatorHLSL.h"
-#include "compiler/translator/DetectDiscontinuity.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/SearchSymbol.h"
#include "compiler/translator/StructureHLSL.h"
#include "compiler/translator/TranslatorHLSL.h"
-#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
+namespace
{
-TString OutputHLSL::TextureFunction::name() const
+bool IsSequence(TIntermNode *node)
{
- TString name = "gl_texture";
+ return node->getAsAggregate() != nullptr && node->getAsAggregate()->getOp() == EOpSequence;
+}
- if (IsSampler2D(sampler))
- {
- name += "2D";
- }
- else if (IsSampler3D(sampler))
- {
- name += "3D";
+void WriteSingleConstant(TInfoSinkBase &out, const TConstantUnion *const constUnion)
+{
+ ASSERT(constUnion != nullptr);
+ switch (constUnion->getType())
+ {
+ case EbtFloat:
+ out << std::min(FLT_MAX, std::max(-FLT_MAX, constUnion->getFConst()));
+ break;
+ case EbtInt:
+ out << constUnion->getIConst();
+ break;
+ case EbtUInt:
+ out << constUnion->getUConst();
+ break;
+ case EbtBool:
+ out << constUnion->getBConst();
+ break;
+ default:
+ UNREACHABLE();
}
- else if (IsSamplerCube(sampler))
+}
+
+const TConstantUnion *WriteConstantUnionArray(TInfoSinkBase &out,
+ const TConstantUnion *const constUnion,
+ const size_t size)
+{
+ const TConstantUnion *constUnionIterated = constUnion;
+ for (size_t i = 0; i < size; i++, constUnionIterated++)
{
- name += "Cube";
+ WriteSingleConstant(out, constUnionIterated);
+
+ if (i != size - 1)
+ {
+ out << ", ";
+ }
}
- else UNREACHABLE();
+ return constUnionIterated;
+}
+
+} // namespace
+
+namespace sh
+{
+
+TString OutputHLSL::TextureFunction::name() const
+{
+ TString name = "gl_texture";
+
+ // We need to include full the sampler type in the function name to make the signature unique
+ // on D3D11, where samplers are passed to texture functions as indices.
+ name += TextureTypeSuffix(this->sampler);
if (proj)
{
@@ -108,10 +144,10 @@ OutputHLSL::OutputHLSL(sh::GLenum shaderType, int shaderVersion,
mExtensionBehavior(extensionBehavior),
mSourcePath(sourcePath),
mOutputType(outputType),
+ mCompileOptions(compileOptions),
mNumRenderTargets(numRenderTargets),
- mCompileOptions(compileOptions)
+ mCurrentFunctionMetadata(nullptr)
{
- mUnfoldShortCircuit = new UnfoldShortCircuit(this);
mInsideFunction = false;
mUsesFragColor = false;
@@ -130,8 +166,6 @@ OutputHLSL::OutputHLSL(sh::GLenum shaderType, int shaderVersion,
mUniqueIndex = 0;
- mContainsLoopDiscontinuity = false;
- mContainsAnyLoop = false;
mOutputLod0Function = false;
mInsideDiscontinuousLoop = false;
mNestedLoopDepth = 0;
@@ -141,7 +175,7 @@ OutputHLSL::OutputHLSL(sh::GLenum shaderType, int shaderVersion,
mStructureHLSL = new StructureHLSL;
mUniformHLSL = new UniformHLSL(mStructureHLSL, outputType, uniforms);
- if (mOutputType == SH_HLSL9_OUTPUT)
+ if (mOutputType == SH_HLSL_3_0_OUTPUT)
{
// Fragment shaders need dx_DepthRange, dx_ViewCoords and dx_DepthFront.
// Vertex shaders need a slightly different set: dx_DepthRange, dx_ViewCoords and dx_ViewAdjust.
@@ -155,37 +189,33 @@ OutputHLSL::OutputHLSL(sh::GLenum shaderType, int shaderVersion,
OutputHLSL::~OutputHLSL()
{
- SafeDelete(mUnfoldShortCircuit);
SafeDelete(mStructureHLSL);
SafeDelete(mUniformHLSL);
- for (auto it = mStructEqualityFunctions.begin(); it != mStructEqualityFunctions.end(); ++it)
+ for (auto &eqFunction : mStructEqualityFunctions)
{
- SafeDelete(*it);
+ SafeDelete(eqFunction);
}
- for (auto it = mArrayEqualityFunctions.begin(); it != mArrayEqualityFunctions.end(); ++it)
+ for (auto &eqFunction : mArrayEqualityFunctions)
{
- SafeDelete(*it);
+ SafeDelete(eqFunction);
}
}
void OutputHLSL::output(TIntermNode *treeRoot, TInfoSinkBase &objSink)
{
- mContainsLoopDiscontinuity = mShaderType == GL_FRAGMENT_SHADER && containsLoopDiscontinuity(treeRoot);
- mContainsAnyLoop = containsAnyLoop(treeRoot);
const std::vector<TIntermTyped*> &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 && mShaderType == GL_VERTEX_SHADER)
- {
- RewriteElseBlocks(treeRoot);
- }
-
BuiltInFunctionEmulator builtInFunctionEmulator;
InitBuiltInFunctionEmulatorForHLSL(&builtInFunctionEmulator);
builtInFunctionEmulator.MarkBuiltInFunctionsForEmulation(treeRoot);
+ // Now that we are done changing the AST, do the analyses need for HLSL generation
+ CallDAG::InitResult success = mCallDag.init(treeRoot, &objSink);
+ ASSERT(success == CallDAG::INITDAG_SUCCESS);
+ UNUSED_ASSERTION_VARIABLE(success);
+ mASTMetadataList = CreateASTMetadataHLSL(treeRoot, mCallDag);
+
// Output the body and footer first to determine what has to go in the header
mInfoSinkStack.push(&mBody);
treeRoot->traverse(this);
@@ -199,7 +229,7 @@ void OutputHLSL::output(TIntermNode *treeRoot, TInfoSinkBase &objSink)
mInfoSinkStack.pop();
mInfoSinkStack.push(&mHeader);
- header(&builtInFunctionEmulator);
+ header(mHeader, &builtInFunctionEmulator);
mInfoSinkStack.pop();
objSink << mHeader.c_str();
@@ -294,10 +324,8 @@ TString OutputHLSL::structInitializerString(int indent, const TStructure &struct
return init;
}
-void OutputHLSL::header(const BuiltInFunctionEmulator *builtInFunctionEmulator)
+void OutputHLSL::header(TInfoSinkBase &out, const BuiltInFunctionEmulator *builtInFunctionEmulator)
{
- TInfoSinkBase &out = getInfoSink();
-
TString varyings;
TString attributes;
TString flaggedStructs;
@@ -334,23 +362,31 @@ void OutputHLSL::header(const BuiltInFunctionEmulator *builtInFunctionEmulator)
out << mStructureHLSL->structsHeader();
- out << mUniformHLSL->uniformsHeader(mOutputType, mReferencedUniforms);
+ mUniformHLSL->uniformsHeader(out, mOutputType, mReferencedUniforms);
out << mUniformHLSL->interfaceBlocksHeader(mReferencedInterfaceBlocks);
if (!mEqualityFunctions.empty())
{
out << "\n// Equality functions\n\n";
- for (auto it = mEqualityFunctions.cbegin(); it != mEqualityFunctions.cend(); ++it)
+ for (const auto &eqFunction : mEqualityFunctions)
{
- out << (*it)->functionDefinition << "\n";
+ out << eqFunction->functionDefinition << "\n";
}
}
if (!mArrayAssignmentFunctions.empty())
{
out << "\n// Assignment functions\n\n";
- for (auto it = mArrayAssignmentFunctions.cbegin(); it != mArrayAssignmentFunctions.cend(); ++it)
+ for (const auto &assignmentFunction : mArrayAssignmentFunctions)
{
- out << it->functionDefinition << "\n";
+ out << assignmentFunction.functionDefinition << "\n";
+ }
+ }
+ if (!mArrayConstructIntoFunctions.empty())
+ {
+ out << "\n// Array constructor functions\n\n";
+ for (const auto &constructIntoFunction : mArrayConstructIntoFunctions)
+ {
+ out << constructIntoFunction.functionDefinition << "\n";
}
}
@@ -449,7 +485,7 @@ void OutputHLSL::header(const BuiltInFunctionEmulator *builtInFunctionEmulator)
"\n";
}
- if (mOutputType == SH_HLSL11_OUTPUT)
+ if (mOutputType == SH_HLSL_4_1_OUTPUT || mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
{
out << "cbuffer DriverConstants : register(b1)\n"
"{\n";
@@ -469,6 +505,13 @@ void OutputHLSL::header(const BuiltInFunctionEmulator *builtInFunctionEmulator)
out << " float3 dx_DepthFront : packoffset(c2);\n";
}
+ if (mUsesFragCoord)
+ {
+ // dx_ViewScale is only used in the fragment shader to correct
+ // the value for glFragCoord if necessary
+ out << " float2 dx_ViewScale : packoffset(c3);\n";
+ }
+
out << "};\n";
}
else
@@ -553,7 +596,7 @@ void OutputHLSL::header(const BuiltInFunctionEmulator *builtInFunctionEmulator)
"\n";
}
- if (mOutputType == SH_HLSL11_OUTPUT)
+ if (mOutputType == SH_HLSL_4_1_OUTPUT || mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
{
out << "cbuffer DriverConstants : register(b1)\n"
"{\n";
@@ -563,11 +606,13 @@ void OutputHLSL::header(const BuiltInFunctionEmulator *builtInFunctionEmulator)
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.
+ // 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 << " float2 dx_ViewScale : packoffset(c3);\n";
out << "};\n"
"\n";
@@ -653,7 +698,7 @@ void OutputHLSL::header(const BuiltInFunctionEmulator *builtInFunctionEmulator)
// Argument list
int hlslCoords = 4;
- if (mOutputType == SH_HLSL9_OUTPUT)
+ if (mOutputType == SH_HLSL_3_0_OUTPUT)
{
switch(textureFunction->sampler)
{
@@ -672,29 +717,20 @@ void OutputHLSL::header(const BuiltInFunctionEmulator *builtInFunctionEmulator)
default: UNREACHABLE();
}
}
- else if (mOutputType == SH_HLSL11_OUTPUT)
+ else
{
- switch(textureFunction->sampler)
+ hlslCoords = HLSLTextureCoordsCount(textureFunction->sampler);
+ if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
{
- case EbtSampler2D: out << "Texture2D x, SamplerState s"; hlslCoords = 2; break;
- case EbtSampler3D: out << "Texture3D x, SamplerState s"; hlslCoords = 3; break;
- case EbtSamplerCube: out << "TextureCube x, SamplerState s"; hlslCoords = 3; break;
- case EbtSampler2DArray: out << "Texture2DArray x, SamplerState s"; hlslCoords = 3; break;
- case EbtISampler2D: out << "Texture2D<int4> x, SamplerState s"; hlslCoords = 2; break;
- case EbtISampler3D: out << "Texture3D<int4> x, SamplerState s"; hlslCoords = 3; break;
- case EbtISamplerCube: out << "Texture2DArray<int4> x, SamplerState s"; hlslCoords = 3; break;
- case EbtISampler2DArray: out << "Texture2DArray<int4> x, SamplerState s"; hlslCoords = 3; break;
- case EbtUSampler2D: out << "Texture2D<uint4> x, SamplerState s"; hlslCoords = 2; break;
- case EbtUSampler3D: out << "Texture3D<uint4> x, SamplerState s"; hlslCoords = 3; break;
- case EbtUSamplerCube: out << "Texture2DArray<uint4> x, SamplerState s"; hlslCoords = 3; break;
- case EbtUSampler2DArray: out << "Texture2DArray<uint4> x, SamplerState s"; hlslCoords = 3; break;
- case EbtSampler2DShadow: out << "Texture2D x, SamplerComparisonState s"; hlslCoords = 2; break;
- case EbtSamplerCubeShadow: out << "TextureCube x, SamplerComparisonState s"; hlslCoords = 3; break;
- case EbtSampler2DArrayShadow: out << "Texture2DArray x, SamplerComparisonState s"; hlslCoords = 3; break;
- default: UNREACHABLE();
+ out << TextureString(textureFunction->sampler) << " x, "
+ << SamplerString(textureFunction->sampler) << " s";
+ }
+ else
+ {
+ ASSERT(mOutputType == SH_HLSL_4_1_OUTPUT);
+ out << "const uint samplerIndex";
}
}
- else UNREACHABLE();
if (textureFunction->method == TextureFunction::FETCH) // Integer coordinates
{
@@ -785,6 +821,31 @@ void OutputHLSL::header(const BuiltInFunctionEmulator *builtInFunctionEmulator)
out << ")\n"
"{\n";
+ // In some cases we use a variable to store the texture/sampler objects, but to work around
+ // a D3D11 compiler bug related to discard inside a loop that is conditional on texture
+ // sampling we need to call the function directly on a reference to the array. The bug was
+ // found using dEQP-GLES3.functional.shaders.discard*loop_texture* tests.
+ TString textureReference("x");
+ TString samplerReference("s");
+ if (mOutputType == SH_HLSL_4_1_OUTPUT)
+ {
+ TString suffix = TextureGroupSuffix(textureFunction->sampler);
+ if (TextureGroup(textureFunction->sampler) == HLSL_TEXTURE_2D)
+ {
+ textureReference = TString("textures") + suffix + "[samplerIndex]";
+ samplerReference = TString("samplers") + suffix + "[samplerIndex]";
+ }
+ else
+ {
+ out << " const uint textureIndex = samplerIndex - textureIndexOffset" << suffix
+ << ";\n";
+ textureReference = TString("textures") + suffix + "[textureIndex]";
+ out << " const uint samplerArrayIndex = samplerIndex - samplerIndexOffset"
+ << suffix << ";\n";
+ samplerReference = TString("samplers") + suffix + "[samplerArrayIndex]";
+ }
+ }
+
if (textureFunction->method == TextureFunction::SIZE)
{
if (IsSampler2D(textureFunction->sampler) || IsSamplerCube(textureFunction->sampler))
@@ -792,18 +853,21 @@ void OutputHLSL::header(const BuiltInFunctionEmulator *builtInFunctionEmulator)
if (IsSamplerArray(textureFunction->sampler))
{
out << " uint width; uint height; uint layers; uint numberOfLevels;\n"
- " x.GetDimensions(lod, width, height, layers, numberOfLevels);\n";
+ << " " << textureReference
+ << ".GetDimensions(lod, width, height, layers, numberOfLevels);\n";
}
else
{
out << " uint width; uint height; uint numberOfLevels;\n"
- " x.GetDimensions(lod, width, height, numberOfLevels);\n";
+ << " " << textureReference
+ << ".GetDimensions(lod, width, height, numberOfLevels);\n";
}
}
else if (IsSampler3D(textureFunction->sampler))
{
out << " uint width; uint height; uint depth; uint numberOfLevels;\n"
- " x.GetDimensions(lod, width, height, depth, numberOfLevels);\n";
+ << " " << textureReference
+ << ".GetDimensions(lod, width, height, depth, numberOfLevels);\n";
}
else UNREACHABLE();
@@ -835,7 +899,8 @@ void OutputHLSL::header(const BuiltInFunctionEmulator *builtInFunctionEmulator)
out << " uint mip = 0;\n";
- out << " x.GetDimensions(mip, width, height, layers, levels);\n";
+ out << " " << textureReference
+ << ".GetDimensions(mip, width, height, layers, levels);\n";
out << " bool xMajor = abs(t.x) > abs(t.y) && abs(t.x) > abs(t.z);\n";
out << " bool yMajor = abs(t.y) > abs(t.z) && abs(t.y) > abs(t.x);\n";
@@ -856,6 +921,18 @@ void OutputHLSL::header(const BuiltInFunctionEmulator *builtInFunctionEmulator)
out << " t.x = (u * 0.5f / m) + 0.5f;\n";
out << " t.y = (v * 0.5f / m) + 0.5f;\n";
+
+ // Mip level computation.
+ if (textureFunction->method == TextureFunction::IMPLICIT)
+ {
+ out << " float2 tSized = float2(t.x * width, t.y * height);\n"
+ " float2 dx = ddx(tSized);\n"
+ " float2 dy = ddy(tSized);\n"
+ " float lod = 0.5f * log2(max(dot(dx, dx), dot(dy, dy)));\n"
+ " mip = uint(min(max(round(lod), 0), levels - 1));\n"
+ << " " << textureReferenc