summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/angle/src
diff options
context:
space:
mode:
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.cpp168
-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, 60628 insertions, 19076 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"
+ << " " << textureReference
+ << ".GetDimensions(mip, width, height, layers, levels);\n";
+ }
}
else if (IsIntegerSampler(textureFunction->sampler) &&
textureFunction->method != TextureFunction::FETCH)
@@ -876,11 +953,13 @@ void OutputHLSL::header(const BuiltInFunctionEmulator *builtInFunctionEmulator)
}
else
{
+
+ out << " " << textureReference
+ << ".GetDimensions(0, width, height, layers, levels);\n";
if (textureFunction->method == TextureFunction::IMPLICIT ||
textureFunction->method == TextureFunction::BIAS)
{
- out << " x.GetDimensions(0, width, height, layers, levels);\n"
- " float2 tSized = float2(t.x * width, t.y * height);\n"
+ out << " float2 tSized = float2(t.x * width, t.y * height);\n"
" float dx = length(ddx(tSized));\n"
" float dy = length(ddy(tSized));\n"
" float lod = log2(max(dx, dy));\n";
@@ -892,14 +971,14 @@ void OutputHLSL::header(const BuiltInFunctionEmulator *builtInFunctionEmulator)
}
else if (textureFunction->method == TextureFunction::GRAD)
{
- out << " x.GetDimensions(0, width, height, layers, levels);\n"
- " float lod = log2(max(length(ddx), length(ddy)));\n";
+ out << " float lod = log2(max(length(ddx), length(ddy)));\n";
}
out << " uint mip = uint(min(max(round(lod), 0), levels - 1));\n";
}
- out << " x.GetDimensions(mip, width, height, layers, levels);\n";
+ out << " " << textureReference
+ << ".GetDimensions(mip, width, height, layers, levels);\n";
}
else
{
@@ -915,11 +994,13 @@ void OutputHLSL::header(const BuiltInFunctionEmulator *builtInFunctionEmulator)
}
else
{
+ out << " " << textureReference
+ << ".GetDimensions(0, width, height, levels);\n";
+
if (textureFunction->method == TextureFunction::IMPLICIT ||
textureFunction->method == TextureFunction::BIAS)
{
- out << " x.GetDimensions(0, width, height, levels);\n"
- " float2 tSized = float2(t.x * width, t.y * height);\n"
+ out << " float2 tSized = float2(t.x * width, t.y * height);\n"
" float dx = length(ddx(tSized));\n"
" float dy = length(ddy(tSized));\n"
" float lod = log2(max(dx, dy));\n";
@@ -929,20 +1010,16 @@ void OutputHLSL::header(const BuiltInFunctionEmulator *builtInFunctionEmulator)
out << " lod += bias;\n";
}
}
- else if (textureFunction->method == TextureFunction::LOD)
- {
- out << " x.GetDimensions(0, width, height, levels);\n";
- }
else if (textureFunction->method == TextureFunction::GRAD)
{
- out << " x.GetDimensions(0, width, height, levels);\n"
- " float lod = log2(max(length(ddx), length(ddy)));\n";
+ out << " float lod = log2(max(length(ddx), length(ddy)));\n";
}
out << " uint mip = uint(min(max(round(lod), 0), levels - 1));\n";
}
- out << " x.GetDimensions(mip, width, height, levels);\n";
+ out << " " << textureReference
+ << ".GetDimensions(mip, width, height, levels);\n";
}
}
else if (IsSampler3D(textureFunction->sampler))
@@ -959,11 +1036,14 @@ void OutputHLSL::header(const BuiltInFunctionEmulator *builtInFunctionEmulator)
}
else
{
+ out << " " << textureReference
+ << ".GetDimensions(0, width, height, depth, levels);\n";
+
if (textureFunction->method == TextureFunction::IMPLICIT ||
textureFunction->method == TextureFunction::BIAS)
{
- out << " x.GetDimensions(0, width, height, depth, levels);\n"
- " float3 tSized = float3(t.x * width, t.y * height, t.z * depth);\n"
+ out << " float3 tSized = float3(t.x * width, t.y * height, t.z * "
+ "depth);\n"
" float dx = length(ddx(tSized));\n"
" float dy = length(ddy(tSized));\n"
" float lod = log2(max(dx, dy));\n";
@@ -975,14 +1055,14 @@ void OutputHLSL::header(const BuiltInFunctionEmulator *builtInFunctionEmulator)
}
else if (textureFunction->method == TextureFunction::GRAD)
{
- out << " x.GetDimensions(0, width, height, depth, levels);\n"
- " float lod = log2(max(length(ddx), length(ddy)));\n";
+ out << " float lod = log2(max(length(ddx), length(ddy)));\n";
}
out << " uint mip = uint(min(max(round(lod), 0), levels - 1));\n";
}
- out << " x.GetDimensions(mip, width, height, depth, levels);\n";
+ out << " " << textureReference
+ << ".GetDimensions(mip, width, height, depth, levels);\n";
}
else UNREACHABLE();
}
@@ -990,7 +1070,7 @@ void OutputHLSL::header(const BuiltInFunctionEmulator *builtInFunctionEmulator)
out << " return ";
// HLSL intrinsic
- if (mOutputType == SH_HLSL9_OUTPUT)
+ if (mOutputType == SH_HLSL_3_0_OUTPUT)
{
switch(textureFunction->sampler)
{
@@ -1001,45 +1081,71 @@ void OutputHLSL::header(const BuiltInFunctionEmulator *builtInFunctionEmulator)
switch(textureFunction->method)
{
- case TextureFunction::IMPLICIT: out << "(s, "; break;
- case TextureFunction::BIAS: out << "bias(s, "; break;
- case TextureFunction::LOD: out << "lod(s, "; break;
- case TextureFunction::LOD0: out << "lod(s, "; break;
- case TextureFunction::LOD0BIAS: out << "lod(s, "; break;
+ case TextureFunction::IMPLICIT:
+ out << "(" << samplerReference << ", ";
+ break;
+ case TextureFunction::BIAS:
+ out << "bias(" << samplerReference << ", ";
+ break;
+ case TextureFunction::LOD:
+ out << "lod(" << samplerReference << ", ";
+ break;
+ case TextureFunction::LOD0:
+ out << "lod(" << samplerReference << ", ";
+ break;
+ case TextureFunction::LOD0BIAS:
+ out << "lod(" << samplerReference << ", ";
+ break;
default: UNREACHABLE();
}
}
- else if (mOutputType == SH_HLSL11_OUTPUT)
+ else if (mOutputType == SH_HLSL_4_1_OUTPUT || mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
{
if (textureFunction->method == TextureFunction::GRAD)
{
if (IsIntegerSampler(textureFunction->sampler))
{
- out << "x.Load(";
+ out << "" << textureReference << ".Load(";
}
else if (IsShadowSampler(textureFunction->sampler))
{
- out << "x.SampleCmpLevelZero(s, ";
+ out << "" << textureReference << ".SampleCmpLevelZero(" << samplerReference
+ << ", ";
}
else
{
- out << "x.SampleGrad(s, ";
+ out << "" << textureReference << ".SampleGrad(" << samplerReference << ", ";
}
}
else if (IsIntegerSampler(textureFunction->sampler) ||
textureFunction->method == TextureFunction::FETCH)
{
- out << "x.Load(";
+ out << "" << textureReference << ".Load(";
}
else if (IsShadowSampler(textureFunction->sampler))
{
switch(textureFunction->method)
{
- case TextureFunction::IMPLICIT: out << "x.SampleCmp(s, "; break;
- case TextureFunction::BIAS: out << "x.SampleCmp(s, "; break;
- case TextureFunction::LOD: out << "x.SampleCmp(s, "; break;
- case TextureFunction::LOD0: out << "x.SampleCmpLevelZero(s, "; break;
- case TextureFunction::LOD0BIAS: out << "x.SampleCmpLevelZero(s, "; break;
+ case TextureFunction::IMPLICIT:
+ out << "" << textureReference << ".SampleCmp(" << samplerReference
+ << ", ";
+ break;
+ case TextureFunction::BIAS:
+ out << "" << textureReference << ".SampleCmp(" << samplerReference
+ << ", ";
+ break;
+ case TextureFunction::LOD:
+ out << "" << textureReference << ".SampleCmp(" << samplerReference
+ << ", ";
+ break;
+ case TextureFunction::LOD0:
+ out << "" << textureReference << ".SampleCmpLevelZero("
+ << samplerReference << ", ";
+ break;
+ case TextureFunction::LOD0BIAS:
+ out << "" << textureReference << ".SampleCmpLevelZero("
+ << samplerReference << ", ";
+ break;
default: UNREACHABLE();
}
}
@@ -1047,11 +1153,25 @@ void OutputHLSL::header(const BuiltInFunctionEmulator *builtInFunctionEmulator)
{
switch(textureFunction->method)
{
- case TextureFunction::IMPLICIT: out << "x.Sample(s, "; break;
- case TextureFunction::BIAS: out << "x.SampleBias(s, "; break;
- case TextureFunction::LOD: out << "x.SampleLevel(s, "; break;
- case TextureFunction::LOD0: out << "x.SampleLevel(s, "; break;
- case TextureFunction::LOD0BIAS: out << "x.SampleLevel(s, "; break;
+ case TextureFunction::IMPLICIT:
+ out << "" << textureReference << ".Sample(" << samplerReference << ", ";
+ break;
+ case TextureFunction::BIAS:
+ out << "" << textureReference << ".SampleBias(" << samplerReference
+ << ", ";
+ break;
+ case TextureFunction::LOD:
+ out << "" << textureReference << ".SampleLevel(" << samplerReference
+ << ", ";
+ break;
+ case TextureFunction::LOD0:
+ out << "" << textureReference << ".SampleLevel(" << samplerReference
+ << ", ";
+ break;
+ case TextureFunction::LOD0BIAS:
+ out << "" << textureReference << ".SampleLevel(" << samplerReference
+ << ", ";
+ break;
default: UNREACHABLE();
}
}
@@ -1121,7 +1241,7 @@ void OutputHLSL::header(const BuiltInFunctionEmulator *builtInFunctionEmulator)
out << addressx + ("t.x" + proj) + close + ", " + addressy + ("t.y" + proj) + close;
- if (mOutputType == SH_HLSL9_OUTPUT)
+ if (mOutputType == SH_HLSL_3_0_OUTPUT)
{
if (hlslCoords >= 3)
{
@@ -1149,7 +1269,7 @@ void OutputHLSL::header(const BuiltInFunctionEmulator *builtInFunctionEmulator)
out << "));\n";
}
- else if (mOutputType == SH_HLSL11_OUTPUT)
+ else if (mOutputType == SH_HLSL_4_1_OUTPUT || mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
{
if (hlslCoords >= 3)
{
@@ -1311,8 +1431,8 @@ void OutputHLSL::visitSymbol(TIntermSymbol *node)
if (qualifier == EvqUniform)
{
- const TType& nodeType = node->getType();
- const TInterfaceBlock* interfaceBlock = nodeType.getInterfaceBlock();
+ const TType &nodeType = node->getType();
+ const TInterfaceBlock *interfaceBlock = nodeType.getInterfaceBlock();
if (interfaceBlock)
{
@@ -1323,6 +1443,8 @@ void OutputHLSL::visitSymbol(TIntermSymbol *node)
mReferencedUniforms[name] = node;
}
+ ensureStructDefined(nodeType);
+
out << DecorateUniform(name, nodeType);
}
else if (qualifier == EvqAttribute || qualifier == EvqVertexIn)
@@ -1375,18 +1497,14 @@ void OutputHLSL::visitSymbol(TIntermSymbol *node)
mUsesInstanceID = true;
out << name;
}
- else if (name == "gl_FragDepthEXT")
+ else if (name == "gl_FragDepthEXT" || name == "gl_FragDepth")
{
mUsesFragDepth = true;
out << "gl_Depth";
}
- else if (qualifier == EvqInternal)
- {
- out << name;
- }
else
{
- out << Decorate(name);
+ out << DecorateIfNeeded(node->getName());
}
}
}
@@ -1402,11 +1520,11 @@ void OutputHLSL::outputEqual(Visit visit, const TType &type, TOperator op, TInfo
{
if (op == EOpEqual)
{
- outputTriplet(visit, "(", " == ", ")", out);
+ outputTriplet(out, visit, "(", " == ", ")");
}
else
{
- outputTriplet(visit, "(", " != ", ")", out);
+ outputTriplet(out, visit, "(", " != ", ")");
}
}
else
@@ -1419,18 +1537,18 @@ void OutputHLSL::outputEqual(Visit visit, const TType &type, TOperator op, TInfo
if (type.isArray())
{
const TString &functionName = addArrayEqualityFunction(type);
- outputTriplet(visit, (functionName + "(").c_str(), ", ", ")", out);
+ outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
}
else if (type.getBasicType() == EbtStruct)
{
const TStructure &structure = *type.getStruct();
const TString &functionName = addStructEqualityFunction(structure);
- outputTriplet(visit, (functionName + "(").c_str(), ", ", ")", out);
+ outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
}
else
{
ASSERT(type.isMatrix() || type.isVector());
- outputTriplet(visit, "all(", " == ", ")", out);
+ outputTriplet(out, visit, "all(", " == ", ")");
}
}
}
@@ -1451,12 +1569,30 @@ bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
case EOpAssign:
if (node->getLeft()->isArray())
{
+ TIntermAggregate *rightAgg = node->getRight()->getAsAggregate();
+ if (rightAgg != nullptr && rightAgg->isConstructor())
+ {
+ const TString &functionName = addArrayConstructIntoFunction(node->getType());
+ out << functionName << "(";
+ node->getLeft()->traverse(this);
+ TIntermSequence *seq = rightAgg->getSequence();
+ for (auto &arrayElement : *seq)
+ {
+ out << ", ";
+ arrayElement->traverse(this);
+ }
+ out << ")";
+ return false;
+ }
+ // ArrayReturnValueToOutParameter should have eliminated expressions where a function call is assigned.
+ ASSERT(rightAgg == nullptr || rightAgg->getOp() != EOpFunctionCall);
+
const TString &functionName = addArrayAssignmentFunction(node->getType());
- outputTriplet(visit, (functionName + "(").c_str(), ", ", ")");
+ outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
}
else
{
- outputTriplet(visit, "(", " = ", ")");
+ outputTriplet(out, visit, "(", " = ", ")");
}
break;
case EOpInitialize:
@@ -1475,8 +1611,12 @@ bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
if (symbolNode->getQualifier() == EvqGlobal && expression->getQualifier() != EvqConst)
{
// For variables which are not constant, defer their real initialization until
- // after we initialize other globals: uniforms, attributes and varyings.
- mDeferredGlobalInitializers.push_back(std::make_pair(symbolNode, expression));
+ // after we initialize uniforms.
+ TIntermBinary *deferredInit = new TIntermBinary(EOpAssign);
+ deferredInit->setLeft(node->getLeft());
+ deferredInit->setRight(node->getRight());
+ deferredInit->setType(node->getType());
+ mDeferredGlobalInitializers.push_back(deferredInit);
const TString &initString = initializer(node->getType());
node->setRight(new TIntermRaw(node->getType(), initString));
}
@@ -1485,17 +1625,31 @@ bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
// Skip initializing the rest of the expression
return false;
}
+ else if (writeConstantInitialization(out, symbolNode, expression))
+ {
+ return false;
+ }
}
else if (visit == InVisit)
{
out << " = ";
}
break;
- case EOpAddAssign: outputTriplet(visit, "(", " += ", ")"); break;
- case EOpSubAssign: outputTriplet(visit, "(", " -= ", ")"); break;
- case EOpMulAssign: outputTriplet(visit, "(", " *= ", ")"); break;
- case EOpVectorTimesScalarAssign: outputTriplet(visit, "(", " *= ", ")"); break;
- case EOpMatrixTimesScalarAssign: outputTriplet(visit, "(", " *= ", ")"); break;
+ case EOpAddAssign:
+ outputTriplet(out, visit, "(", " += ", ")");
+ break;
+ case EOpSubAssign:
+ outputTriplet(out, visit, "(", " -= ", ")");
+ break;
+ case EOpMulAssign:
+ outputTriplet(out, visit, "(", " *= ", ")");
+ break;
+ case EOpVectorTimesScalarAssign:
+ outputTriplet(out, visit, "(", " *= ", ")");
+ break;
+ case EOpMatrixTimesScalarAssign:
+ outputTriplet(out, visit, "(", " *= ", ")");
+ break;
case EOpVectorTimesMatrixAssign:
if (visit == PreVisit)
{
@@ -1528,13 +1682,27 @@ bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
out << "))))";
}
break;
- case EOpDivAssign: outputTriplet(visit, "(", " /= ", ")"); break;
- case EOpIModAssign: outputTriplet(visit, "(", " %= ", ")"); break;
- case EOpBitShiftLeftAssign: outputTriplet(visit, "(", " <<= ", ")"); break;
- case EOpBitShiftRightAssign: outputTriplet(visit, "(", " >>= ", ")"); break;
- case EOpBitwiseAndAssign: outputTriplet(visit, "(", " &= ", ")"); break;
- case EOpBitwiseXorAssign: outputTriplet(visit, "(", " ^= ", ")"); break;
- case EOpBitwiseOrAssign: outputTriplet(visit, "(", " |= ", ")"); break;
+ case EOpDivAssign:
+ outputTriplet(out, visit, "(", " /= ", ")");
+ break;
+ case EOpIModAssign:
+ outputTriplet(out, visit, "(", " %= ", ")");
+ break;
+ case EOpBitShiftLeftAssign:
+ outputTriplet(out, visit, "(", " <<= ", ")");
+ break;
+ case EOpBitShiftRightAssign:
+ outputTriplet(out, visit, "(", " >>= ", ")");
+ break;
+ case EOpBitwiseAndAssign:
+ outputTriplet(out, visit, "(", " &= ", ")");
+ break;
+ case EOpBitwiseXorAssign:
+ outputTriplet(out, visit, "(", " ^= ", ")");
+ break;
+ case EOpBitwiseOrAssign:
+ outputTriplet(out, visit, "(", " |= ", ")");
+ break;
case EOpIndexDirect:
{
const TType& leftType = node->getLeft()->getType();
@@ -1551,14 +1719,14 @@ bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
}
else
{
- outputTriplet(visit, "", "[", "]");
+ outputTriplet(out, visit, "", "[", "]");
}
}
break;
case EOpIndexIndirect:
// We do not currently support indirect references to interface blocks
ASSERT(node->getLeft()->getBasicType() != EbtInterfaceBlock);
- outputTriplet(visit, "", "[", "]");
+ outputTriplet(out, visit, "", "[", "]");
break;
case EOpIndexDirectStruct:
if (visit == InVisit)
@@ -1618,55 +1786,81 @@ bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
return false; // Fully processed
}
break;
- case EOpAdd: outputTriplet(visit, "(", " + ", ")"); break;
- case EOpSub: outputTriplet(visit, "(", " - ", ")"); break;
- case EOpMul: outputTriplet(visit, "(", " * ", ")"); break;
- case EOpDiv: outputTriplet(visit, "(", " / ", ")"); break;
- case EOpIMod: outputTriplet(visit, "(", " % ", ")"); break;
- case EOpBitShiftLeft: outputTriplet(visit, "(", " << ", ")"); break;
- case EOpBitShiftRight: outputTriplet(visit, "(", " >> ", ")"); break;
- case EOpBitwiseAnd: outputTriplet(visit, "(", " & ", ")"); break;
- case EOpBitwiseXor: outputTriplet(visit, "(", " ^ ", ")"); break;
- case EOpBitwiseOr: outputTriplet(visit, "(", " | ", ")"); break;
+ case EOpAdd:
+ outputTriplet(out, visit, "(", " + ", ")");
+ break;
+ case EOpSub:
+ outputTriplet(out, visit, "(", " - ", ")");
+ break;
+ case EOpMul:
+ outputTriplet(out, visit, "(", " * ", ")");
+ break;
+ case EOpDiv:
+ outputTriplet(out, visit, "(", " / ", ")");
+ break;
+ case EOpIMod:
+ outputTriplet(out, visit, "(", " % ", ")");
+ break;
+ case EOpBitShiftLeft:
+ outputTriplet(out, visit, "(", " << ", ")");
+ break;
+ case EOpBitShiftRight:
+ outputTriplet(out, visit, "(", " >> ", ")");
+ break;
+ case EOpBitwiseAnd:
+ outputTriplet(out, visit, "(", " & ", ")");
+ break;
+ case EOpBitwiseXor:
+ outputTriplet(out, visit, "(", " ^ ", ")");
+ break;
+ case EOpBitwiseOr:
+ outputTriplet(out, visit, "(", " | ", ")");
+ break;
case EOpEqual:
case EOpNotEqual:
outputEqual(visit, node->getLeft()->getType(), node->getOp(), out);
break;
- case EOpLessThan: outputTriplet(visit, "(", " < ", ")"); break;
- case EOpGreaterThan: outputTriplet(visit, "(", " > ", ")"); break;
- case EOpLessThanEqual: outputTriplet(visit, "(", " <= ", ")"); break;
- case EOpGreaterThanEqual: outputTriplet(visit, "(", " >= ", ")"); break;
- case EOpVectorTimesScalar: outputTriplet(visit, "(", " * ", ")"); break;
- case EOpMatrixTimesScalar: outputTriplet(visit, "(", " * ", ")"); break;
- case EOpVectorTimesMatrix: outputTriplet(visit, "mul(", ", transpose(", "))"); break;
- case EOpMatrixTimesVector: outputTriplet(visit, "mul(transpose(", "), ", ")"); break;
- case EOpMatrixTimesMatrix: outputTriplet(visit, "transpose(mul(transpose(", "), transpose(", ")))"); break;
+ case EOpLessThan:
+ outputTriplet(out, visit, "(", " < ", ")");
+ break;
+ case EOpGreaterThan:
+ outputTriplet(out, visit, "(", " > ", ")");
+ break;
+ case EOpLessThanEqual:
+ outputTriplet(out, visit, "(", " <= ", ")");
+ break;
+ case EOpGreaterThanEqual:
+ outputTriplet(out, visit, "(", " >= ", ")");
+ break;
+ case EOpVectorTimesScalar:
+ outputTriplet(out, visit, "(", " * ", ")");
+ break;
+ case EOpMatrixTimesScalar:
+ outputTriplet(out, visit, "(", " * ", ")");
+ break;
+ case EOpVectorTimesMatrix:
+ outputTriplet(out, visit, "mul(", ", transpose(", "))");
+ break;
+ case EOpMatrixTimesVector:
+ outputTriplet(out, visit, "mul(transpose(", "), ", ")");
+ break;
+ case EOpMatrixTimesMatrix:
+ outputTriplet(out, visit, "transpose(mul(transpose(", "), transpose(", ")))");
+ break;
case EOpLogicalOr:
- if (node->getRight()->hasSideEffects())
- {
- out << "s" << mUnfoldShortCircuit->getNextTemporaryIndex();
- return false;
- }
- else
- {
- outputTriplet(visit, "(", " || ", ")");
- return true;
- }
+ // HLSL doesn't short-circuit ||, so we assume that || affected by short-circuiting have been unfolded.
+ ASSERT(!node->getRight()->hasSideEffects());
+ outputTriplet(out, visit, "(", " || ", ")");
+ return true;
case EOpLogicalXor:
mUsesXor = true;
- outputTriplet(visit, "xor(", ", ", ")");
+ outputTriplet(out, visit, "xor(", ", ", ")");
break;
case EOpLogicalAnd:
- if (node->getRight()->hasSideEffects())
- {
- out << "s" << mUnfoldShortCircuit->getNextTemporaryIndex();
- return false;
- }
- else
- {
- outputTriplet(visit, "(", " && ", ")");
- return true;
- }
+ // HLSL doesn't short-circuit &&, so we assume that && affected by short-circuiting have been unfolded.
+ ASSERT(!node->getRight()->hasSideEffects());
+ outputTriplet(out, visit, "(", " && ", ")");
+ return true;
default: UNREACHABLE();
}
@@ -1675,131 +1869,221 @@ bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node)
{
+ TInfoSinkBase &out = getInfoSink();
+
switch (node->getOp())
{
- case EOpNegative: outputTriplet(visit, "(-", "", ")"); break;
- case EOpPositive: outputTriplet(visit, "(+", "", ")"); break;
- case EOpVectorLogicalNot: outputTriplet(visit, "(!", "", ")"); break;
- case EOpLogicalNot: outputTriplet(visit, "(!", "", ")"); break;
- case EOpBitwiseNot: outputTriplet(visit, "(~", "", ")"); break;
- case EOpPostIncrement: outputTriplet(visit, "(", "", "++)"); break;
- case EOpPostDecrement: outputTriplet(visit, "(", "", "--)"); break;
- case EOpPreIncrement: outputTriplet(visit, "(++", "", ")"); break;
- case EOpPreDecrement: outputTriplet(visit, "(--", "", ")"); break;
- case EOpRadians: outputTriplet(visit, "radians(", "", ")"); break;
- case EOpDegrees: outputTriplet(visit, "degrees(", "", ")"); break;
- case EOpSin: outputTriplet(visit, "sin(", "", ")"); break;
- case EOpCos: outputTriplet(visit, "cos(", "", ")"); break;
- case EOpTan: outputTriplet(visit, "tan(", "", ")"); break;
- case EOpAsin: outputTriplet(visit, "asin(", "", ")"); break;
- case EOpAcos: outputTriplet(visit, "acos(", "", ")"); break;
- case EOpAtan: outputTriplet(visit, "atan(", "", ")"); break;
- case EOpSinh: outputTriplet(visit, "sinh(", "", ")"); break;
- case EOpCosh: outputTriplet(visit, "cosh(", "", ")"); break;
- case EOpTanh: outputTriplet(visit, "tanh(", "", ")"); break;
+ case EOpNegative:
+ outputTriplet(out, visit, "(-", "", ")");
+ break;
+ case EOpPositive:
+ outputTriplet(out, visit, "(+", "", ")");
+ break;
+ case EOpVectorLogicalNot:
+ outputTriplet(out, visit, "(!", "", ")");
+ break;
+ case EOpLogicalNot:
+ outputTriplet(out, visit, "(!", "", ")");
+ break;
+ case EOpBitwiseNot:
+ outputTriplet(out, visit, "(~", "", ")");
+ break;
+ case EOpPostIncrement:
+ outputTriplet(out, visit, "(", "", "++)");
+ break;
+ case EOpPostDecrement:
+ outputTriplet(out, visit, "(", "", "--)");
+ break;
+ case EOpPreIncrement:
+ outputTriplet(out, visit, "(++", "", ")");
+ break;
+ case EOpPreDecrement:
+ outputTriplet(out, visit, "(--", "", ")");
+ break;
+ case EOpRadians:
+ outputTriplet(out, visit, "radians(", "", ")");
+ break;
+ case EOpDegrees:
+ outputTriplet(out, visit, "degrees(", "", ")");
+ break;
+ case EOpSin:
+ outputTriplet(out, visit, "sin(", "", ")");
+ break;
+ case EOpCos:
+ outputTriplet(out, visit, "cos(", "", ")");
+ break;
+ case EOpTan:
+ outputTriplet(out, visit, "tan(", "", ")");
+ break;
+ case EOpAsin:
+ outputTriplet(out, visit, "asin(", "", ")");
+ break;
+ case EOpAcos:
+ outputTriplet(out, visit, "acos(", "", ")");
+ break;
+ case EOpAtan:
+ outputTriplet(out, visit, "atan(", "", ")");
+ break;
+ case EOpSinh:
+ outputTriplet(out, visit, "sinh(", "", ")");
+ break;
+ case EOpCosh:
+ outputTriplet(out, visit, "cosh(", "", ")");
+ break;
+ case EOpTanh:
+ outputTriplet(out, visit, "tanh(", "", ")");
+ break;
case EOpAsinh:
ASSERT(node->getUseEmulatedFunction());
- writeEmulatedFunctionTriplet(visit, "asinh(");
+ writeEmulatedFunctionTriplet(out, visit, "asinh(");
break;
case EOpAcosh:
ASSERT(node->getUseEmulatedFunction());
- writeEmulatedFunctionTriplet(visit, "acosh(");
+ writeEmulatedFunctionTriplet(out, visit, "acosh(");
break;
case EOpAtanh:
ASSERT(node->getUseEmulatedFunction());
- writeEmulatedFunctionTriplet(visit, "atanh(");
+ writeEmulatedFunctionTriplet(out, visit, "atanh(");
break;
- case EOpExp: outputTriplet(visit, "exp(", "", ")"); break;
- case EOpLog: outputTriplet(visit, "log(", "", ")"); break;
- case EOpExp2: outputTriplet(visit, "exp2(", "", ")"); break;
- case EOpLog2: outputTriplet(visit, "log2(", "", ")"); break;
- case EOpSqrt: outputTriplet(visit, "sqrt(", "", ")"); break;
- case EOpInverseSqrt: outputTriplet(visit, "rsqrt(", "", ")"); break;
- case EOpAbs: outputTriplet(visit, "abs(", "", ")"); break;
- case EOpSign: outputTriplet(visit, "sign(", "", ")"); break;
- case EOpFloor: outputTriplet(visit, "floor(", "", ")"); break;
- case EOpTrunc: outputTriplet(visit, "trunc(", "", ")"); break;
- case EOpRound: outputTriplet(visit, "round(", "", ")"); break;
+ case EOpExp:
+ outputTriplet(out, visit, "exp(", "", ")");
+ break;
+ case EOpLog:
+ outputTriplet(out, visit, "log(", "", ")");
+ break;
+ case EOpExp2:
+ outputTriplet(out, visit, "exp2(", "", ")");
+ break;
+ case EOpLog2:
+ outputTriplet(out, visit, "log2(", "", ")");
+ break;
+ case EOpSqrt:
+ outputTriplet(out, visit, "sqrt(", "", ")");
+ break;
+ case EOpInverseSqrt:
+ outputTriplet(out, visit, "rsqrt(", "", ")");
+ break;
+ case EOpAbs:
+ outputTriplet(out, visit, "abs(", "", ")");
+ break;
+ case EOpSign:
+ outputTriplet(out, visit, "sign(", "", ")");
+ break;
+ case EOpFloor:
+ outputTriplet(out, visit, "floor(", "", ")");
+ break;
+ case EOpTrunc:
+ outputTriplet(out, visit, "trunc(", "", ")");
+ break;
+ case EOpRound:
+ outputTriplet(out, visit, "round(", "", ")");
+ break;
case EOpRoundEven:
ASSERT(node->getUseEmulatedFunction());
- writeEmulatedFunctionTriplet(visit, "roundEven(");
+ writeEmulatedFunctionTriplet(out, visit, "roundEven(");
break;
- case EOpCeil: outputTriplet(visit, "ceil(", "", ")"); break;
- case EOpFract: outputTriplet(visit, "frac(", "", ")"); break;
+ case EOpCeil:
+ outputTriplet(out, visit, "ceil(", "", ")");
+ break;
+ case EOpFract:
+ outputTriplet(out, visit, "frac(", "", ")");
+ break;
case EOpIsNan:
- outputTriplet(visit, "isnan(", "", ")");
+ outputTriplet(out, visit, "isnan(", "", ")");
mRequiresIEEEStrictCompiling = true;
break;
- case EOpIsInf: outputTriplet(visit, "isinf(", "", ")"); break;
- case EOpFloatBitsToInt: outputTriplet(visit, "asint(", "", ")"); break;
- case EOpFloatBitsToUint: outputTriplet(visit, "asuint(", "", ")"); break;
- case EOpIntBitsToFloat: outputTriplet(visit, "asfloat(", "", ")"); break;
- case EOpUintBitsToFloat: outputTriplet(visit, "asfloat(", "", ")"); break;
+ case EOpIsInf:
+ outputTriplet(out, visit, "isinf(", "", ")");
+ break;
+ case EOpFloatBitsToInt:
+ outputTriplet(out, visit, "asint(", "", ")");
+ break;
+ case EOpFloatBitsToUint:
+ outputTriplet(out, visit, "asuint(", "", ")");
+ break;
+ case EOpIntBitsToFloat:
+ outputTriplet(out, visit, "asfloat(", "", ")");
+ break;
+ case EOpUintBitsToFloat:
+ outputTriplet(out, visit, "asfloat(", "", ")");
+ break;
case EOpPackSnorm2x16:
ASSERT(node->getUseEmulatedFunction());
- writeEmulatedFunctionTriplet(visit, "packSnorm2x16(");
+ writeEmulatedFunctionTriplet(out, visit, "packSnorm2x16(");
break;
case EOpPackUnorm2x16:
ASSERT(node->getUseEmulatedFunction());
- writeEmulatedFunctionTriplet(visit, "packUnorm2x16(");
+ writeEmulatedFunctionTriplet(out, visit, "packUnorm2x16(");
break;
case EOpPackHalf2x16:
ASSERT(node->getUseEmulatedFunction());
- writeEmulatedFunctionTriplet(visit, "packHalf2x16(");
+ writeEmulatedFunctionTriplet(out, visit, "packHalf2x16(");
break;
case EOpUnpackSnorm2x16:
ASSERT(node->getUseEmulatedFunction());
- writeEmulatedFunctionTriplet(visit, "unpackSnorm2x16(");
+ writeEmulatedFunctionTriplet(out, visit, "unpackSnorm2x16(");
break;
case EOpUnpackUnorm2x16:
ASSERT(node->getUseEmulatedFunction());
- writeEmulatedFunctionTriplet(visit, "unpackUnorm2x16(");
+ writeEmulatedFunctionTriplet(out, visit, "unpackUnorm2x16(");
break;
case EOpUnpackHalf2x16:
ASSERT(node->getUseEmulatedFunction());
- writeEmulatedFunctionTriplet(visit, "unpackHalf2x16(");
+ writeEmulatedFunctionTriplet(out, visit, "unpackHalf2x16(");
break;
- case EOpLength: outputTriplet(visit, "length(", "", ")"); break;
- case EOpNormalize: outputTriplet(visit, "normalize(", "", ")"); break;
+ case EOpLength:
+ outputTriplet(out, visit, "length(", "", ")");
+ break;
+ case EOpNormalize:
+ outputTriplet(out, visit, "normalize(", "", ")");
+ break;
case EOpDFdx:
if(mInsideDiscontinuousLoop || mOutputLod0Function)
{
- outputTriplet(visit, "(", "", ", 0.0)");
+ outputTriplet(out, visit, "(", "", ", 0.0)");
}
else
{
- outputTriplet(visit, "ddx(", "", ")");
+ outputTriplet(out, visit, "ddx(", "", ")");
}
break;
case EOpDFdy:
if(mInsideDiscontinuousLoop || mOutputLod0Function)
{
- outputTriplet(visit, "(", "", ", 0.0)");
+ outputTriplet(out, visit, "(", "", ", 0.0)");
}
else
{
- outputTriplet(visit, "ddy(", "", ")");
+ outputTriplet(out, visit, "ddy(", "", ")");
}
break;
case EOpFwidth:
if(mInsideDiscontinuousLoop || mOutputLod0Function)
{
- outputTriplet(visit, "(", "", ", 0.0)");
+ outputTriplet(out, visit, "(", "", ", 0.0)");
}
else
{
- outputTriplet(visit, "fwidth(", "", ")");
+ outputTriplet(out, visit, "fwidth(", "", ")");
}
break;
- case EOpTranspose: outputTriplet(visit, "transpose(", "", ")"); break;
- case EOpDeterminant: outputTriplet(visit, "determinant(transpose(", "", "))"); break;
+ case EOpTranspose:
+ outputTriplet(out, visit, "transpose(", "", ")");
+ break;
+ case EOpDeterminant:
+ outputTriplet(out, visit, "determinant(transpose(", "", "))");
+ break;
case EOpInverse:
ASSERT(node->getUseEmulatedFunction());
- writeEmulatedFunctionTriplet(visit, "inverse(");
+ writeEmulatedFunctionTriplet(out, visit, "inverse(");
break;
- case EOpAny: outputTriplet(visit, "any(", "", ")"); break;
- case EOpAll: outputTriplet(visit, "all(", "", ")"); break;
+ case EOpAny:
+ outputTriplet(out, visit, "any(", "", ")");
+ break;
+ case EOpAll:
+ outputTriplet(out, visit, "all(", "", ")");
+ break;
default: UNREACHABLE();
}
@@ -1816,26 +2100,30 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
{
if (mInsideFunction)
{
- outputLineDirective(node->getLine().first_line);
+ outputLineDirective(out, node->getLine().first_line);
out << "{\n";
}
for (TIntermSequence::iterator sit = node->getSequence()->begin(); sit != node->getSequence()->end(); sit++)
{
- outputLineDirective((*sit)->getLine().first_line);
+ outputLineDirective(out, (*sit)->getLine().first_line);
- traverseStatements(*sit);
+ (*sit)->traverse(this);
// Don't output ; after case labels, they're terminated by :
// This is needed especially since outputting a ; after a case statement would turn empty
// case statements into non-empty case statements, disallowing fall-through from them.
- if ((*sit)->getAsCaseNode() == nullptr)
+ // Also no need to output ; after selection (if) statements or sequences. This is done just
+ // for code clarity.
+ TIntermSelection *asSelection = (*sit)->getAsSelectionNode();
+ ASSERT(asSelection == nullptr || !asSelection->usesTernaryOperator());
+ if ((*sit)->getAsCaseNode() == nullptr && asSelection == nullptr && !IsSequence(*sit))
out << ";\n";
}
if (mInsideFunction)
{
- outputLineDirective(node->getLine().last_line);
+ outputLineDirective(out, node->getLine().last_line);
out << "}\n";
}
@@ -1846,50 +2134,34 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
{
TIntermSequence *sequence = node->getSequence();
TIntermTyped *variable = (*sequence)[0]->getAsTyped();
+ ASSERT(sequence->size() == 1);
- if (variable && (variable->getQualifier() == EvqTemporary || variable->getQualifier() == EvqGlobal))
+ if (variable &&
+ (variable->getQualifier() == EvqTemporary ||
+ variable->getQualifier() == EvqGlobal || variable->getQualifier() == EvqConst))
{
- TStructure *structure = variable->getType().getStruct();
-
- if (structure)
- {
- mStructureHLSL->addConstructor(variable->getType(), StructNameString(*structure), NULL);
- }
+ ensureStructDefined(variable->getType());
if (!variable->getAsSymbolNode() || variable->getAsSymbolNode()->getSymbol() != "") // Variable declaration
{
- for (auto it = sequence->cbegin(); it != sequence->cend(); ++it)
+ if (!mInsideFunction)
{
- const auto &seqElement = *it;
- if (isSingleStatement(seqElement))
- {
- mUnfoldShortCircuit->traverse(seqElement);
- }
-
- if (!mInsideFunction)
- {
- out << "static ";
- }
+ out << "static ";
+ }
- out << TypeString(variable->getType()) + " ";
+ out << TypeString(variable->getType()) + " ";
- TIntermSymbol *symbol = seqElement->getAsSymbolNode();
+ TIntermSymbol *symbol = variable->getAsSymbolNode();
- if (symbol)
- {
- symbol->traverse(this);
- out << ArrayString(symbol->getType());
- out << " = " + initializer(symbol->getType());
- }
- else
- {
- seqElement->traverse(this);
- }
-
- if (seqElement != sequence->back())
- {
- out << ";\n";
- }
+ if (symbol)
+ {
+ symbol->traverse(this);
+ out << ArrayString(symbol->getType());
+ out << " = " + initializer(symbol->getType());
+ }
+ else
+ {
+ variable->traverse(this);
}
}
else if (variable->getAsSymbolNode() && variable->getAsSymbolNode()->getSymbol() == "") // Type (struct) declaration
@@ -1929,7 +2201,16 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
case EOpPrototype:
if (visit == PreVisit)
{
- out << TypeString(node->getType()) << " " << Decorate(TFunction::unmangleName(node->getName())) << (mOutputLod0Function ? "Lod0(" : "(");
+ size_t index = mCallDag.findIndex(node);
+ // Skip the prototype if it is not implemented (and thus not used)
+ if (index == CallDAG::InvalidIndex)
+ {
+ return false;
+ }
+
+ TString name = DecorateFunctionIfNeeded(node->getNameObj());
+ out << TypeString(node->getType()) << " " << name
+ << (mOutputLod0Function ? "Lod0(" : "(");
TIntermSequence *arguments = node->getSequence();
@@ -1952,7 +2233,8 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
out << ");\n";
// Also prototype the Lod0 variant if needed
- if (mContainsLoopDiscontinuity && !mOutputLod0Function)
+ bool needsLod0 = mASTMetadataList[index].mNeedsLod0;
+ if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
{
mOutputLod0Function = true;
node->traverse(this);
@@ -1962,10 +2244,17 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
return false;
}
break;
- case EOpComma: outputTriplet(visit, "(", ", ", ")"); break;
+ case EOpComma:
+ outputTriplet(out, visit, "(", ", ", ")");
+ break;
case EOpFunction:
{
- TString name = TFunction::unmangleName(node->getName());
+ ASSERT(mCurrentFunctionMetadata == nullptr);
+ TString name = TFunction::unmangleName(node->getNameObj().getString());
+
+ size_t index = mCallDag.findIndex(node);
+ ASSERT(index != CallDAG::InvalidIndex);
+ mCurrentFunctionMetadata = &mASTMetadataList[index];
out << TypeString(node->getType()) << " ";
@@ -1975,7 +2264,8 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
}
else
{
- out << Decorate(name) << (mOutputLod0Function ? "Lod0(" : "(");
+ out << DecorateFunctionIfNeeded(node->getNameObj())
+ << (mOutputLod0Function ? "Lod0(" : "(");
}
TIntermSequence *sequence = node->getSequence();
@@ -1987,12 +2277,7 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
if (symbol)
{
- TStructure *structure = symbol->getType().getStruct();
-
- if (structure)
- {
- mStructureHLSL->addConstructor(symbol->getType(), StructNameString(*structure), NULL);
- }
+ ensureStructDefined(symbol->getType());
out << argumentString(symbol);
@@ -2004,26 +2289,31 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
else UNREACHABLE();
}
- out << ")\n"
- "{\n";
+ out << ")\n";
if (sequence->size() > 1)
{
mInsideFunction = true;
- (*sequence)[1]->traverse(this);
+ TIntermNode *body = (*sequence)[1];
+ // The function body node will output braces.
+ ASSERT(IsSequence(body));
+ body->traverse(this);
mInsideFunction = false;
}
+ else
+ {
+ out << "{}\n";
+ }
- out << "}\n";
+ mCurrentFunctionMetadata = nullptr;
- if (mContainsLoopDiscontinuity && !mOutputLod0Function)
+ bool needsLod0 = mASTMetadataList[index].mNeedsLod0;
+ if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
{
- if (name != "main")
- {
- mOutputLod0Function = true;
- node->traverse(this);
- mOutputLod0Function = false;
- }
+ ASSERT(name != "main");
+ mOutputLod0Function = true;
+ node->traverse(this);
+ mOutputLod0Function = false;
}
return false;
@@ -2031,16 +2321,24 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
break;
case EOpFunctionCall:
{
- TString name = TFunction::unmangleName(node->getName());
- bool lod0 = mInsideDiscontinuousLoop || mOutputLod0Function;
TIntermSequence *arguments = node->getSequence();
+ bool lod0 = mInsideDiscontinuousLoop || mOutputLod0Function;
if (node->isUserDefined())
{
- out << Decorate(name) << (lod0 ? "Lod0(" : "(");
+ if (node->isArray())
+ {
+ UNIMPLEMENTED();
+ }
+ size_t index = mCallDag.findIndex(node);
+ ASSERT(index != CallDAG::InvalidIndex);
+ lod0 &= mASTMetadataList[index].mNeedsLod0;
+
+ out << DecorateFunctionIfNeeded(node->getNameObj()) << (lod0 ? "Lod0(" : "(");
}
else
{
+ TString name = TFunction::unmangleName(node->getNameObj().getString());
TBasicType samplerType = (*arguments)[0]->getAsTyped()->getType().getBasicType();
TextureFunction textureFunction;
@@ -2161,7 +2459,8 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
for (TIntermSequence::iterator arg = arguments->begin(); arg != arguments->end(); arg++)
{
- if (mOutputType == SH_HLSL11_OUTPUT && IsSampler((*arg)->getAsTyped()->getBasicType()))
+ if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT &&
+ IsSampler((*arg)->getAsTyped()->getBasicType()))
{
out << "texture_";
(*arg)->traverse(this);
@@ -2181,172 +2480,299 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
return false;
}
break;
- case EOpParameters: outputTriplet(visit, "(", ", ", ")\n{\n"); break;
- case EOpConstructFloat: outputConstructor(visit, node->getType(), "vec1", node->getSequence()); break;
- case EOpConstructVec2: outputConstructor(visit, node->getType(), "vec2", node->getSequence()); break;
- case EOpConstructVec3: outputConstructor(visit, node->getType(), "vec3", node->getSequence()); break;
- case EOpConstructVec4: outputConstructor(visit, node->getType(), "vec4", node->getSequence()); break;
- case EOpConstructBool: outputConstructor(visit, node->getType(), "bvec1", node->getSequence()); break;
- case EOpConstructBVec2: outputConstructor(visit, node->getType(), "bvec2", node->getSequence()); break;
- case EOpConstructBVec3: outputConstructor(visit, node->getType(), "bvec3", node->getSequence()); break;
- case EOpConstructBVec4: outputConstructor(visit, node->getType(), "bvec4", node->getSequence()); break;
- case EOpConstructInt: outputConstructor(visit, node->getType(), "ivec1", node->getSequence()); break;
- case EOpConstructIVec2: outputConstructor(visit, node->getType(), "ivec2", node->getSequence()); break;
- case EOpConstructIVec3: outputConstructor(visit, node->getType(), "ivec3", node->getSequence()); break;
- case EOpConstructIVec4: outputConstructor(visit, node->getType(), "ivec4", node->getSequence()); break;
- case EOpConstructUInt: outputConstructor(visit, node->getType(), "uvec1", node->getSequence()); break;
- case EOpConstructUVec2: outputConstructor(visit, node->getType(), "uvec2", node->getSequence()); break;
- case EOpConstructUVec3: outputConstructor(visit, node->getType(), "uvec3", node->getSequence()); break;
- case EOpConstructUVec4: outputConstructor(visit, node->getType(), "uvec4", node->getSequence()); break;
- case EOpConstructMat2: outputConstructor(visit, node->getType(), "mat2", node->getSequence()); break;
- case EOpConstructMat3: outputConstructor(visit, node->getType(), "mat3", node->getSequence()); break;
- case EOpConstructMat4: outputConstructor(visit, node->getType(), "mat4", node->getSequence()); break;
+ case EOpParameters:
+ outputTriplet(out, visit, "(", ", ", ")\n{\n");
+ break;
+ case EOpConstructFloat:
+ outputConstructor(out, visit, node->getType(), "vec1", node->getSequence());
+ break;
+ case EOpConstructVec2:
+ outputConstructor(out, visit, node->getType(), "vec2", node->getSequence());
+ break;
+ case EOpConstructVec3:
+ outputConstructor(out, visit, node->getType(), "vec3", node->getSequence());
+ break;
+ case EOpConstructVec4:
+ outputConstructor(out, visit, node->getType(), "vec4", node->getSequence());
+ break;
+ case EOpConstructBool:
+ outputConstructor(out, visit, node->getType(), "bvec1", node->getSequence());
+ break;
+ case EOpConstructBVec2:
+ outputConstructor(out, visit, node->getType(), "bvec2", node->getSequence());
+ break;
+ case EOpConstructBVec3:
+ outputConstructor(out, visit, node->getType(), "bvec3", node->getSequence());
+ break;
+ case EOpConstructBVec4:
+ outputConstructor(out, visit, node->getType(), "bvec4", node->getSequence());
+ break;
+ case EOpConstructInt:
+ outputConstructor(out, visit, node->getType(), "ivec1", node->getSequence());
+ break;
+ case EOpConstructIVec2:
+ outputConstructor(out, visit, node->getType(), "ivec2", node->getSequence());
+ break;
+ case EOpConstructIVec3:
+ outputConstructor(out, visit, node->getType(), "ivec3", node->getSequence());
+ break;
+ case EOpConstructIVec4:
+ outputConstructor(out, visit, node->getType(), "ivec4", node->getSequence());
+ break;
+ case EOpConstructUInt:
+ outputConstructor(out, visit, node->getType(), "uvec1", node->getSequence());
+ break;
+ case EOpConstructUVec2:
+ outputConstructor(out, visit, node->getType(), "uvec2", node->getSequence());
+ break;
+ case EOpConstructUVec3:
+ outputConstructor(out, visit, node->getType(), "uvec3", node->getSequence());
+ break;
+ case EOpConstructUVec4:
+ outputConstructor(out, visit, node->getType(), "uvec4", node->getSequence());
+ break;
+ case EOpConstructMat2:
+ outputConstructor(out, visit, node->getType(), "mat2", node->getSequence());
+ break;
+ case EOpConstructMat2x3:
+ outputConstructor(out, visit, node->getType(), "mat2x3", node->getSequence());
+ break;
+ case EOpConstructMat2x4:
+ outputConstructor(out, visit, node->getType(), "mat2x4", node->getSequence());
+ break;
+ case EOpConstructMat3x2:
+ outputConstructor(out, visit, node->getType(), "mat3x2", node->getSequence());
+ break;
+ case EOpConstructMat3:
+ outputConstructor(out, visit, node->getType(), "mat3", node->getSequence());
+ break;
+ case EOpConstructMat3x4:
+ outputConstructor(out, visit, node->getType(), "mat3x4", node->getSequence());
+ break;
+ case EOpConstructMat4x2:
+ outputConstructor(out, visit, node->getType(), "mat4x2", node->getSequence());
+ break;
+ case EOpConstructMat4x3:
+ outputConstructor(out, visit, node->getType(), "mat4x3", node->getSequence());
+ break;
+ case EOpConstructMat4:
+ outputConstructor(out, visit, node->getType(), "mat4", node->getSequence());
+ break;
case EOpConstructStruct:
{
+ if (node->getType().isArray())
+ {
+ UNIMPLEMENTED();
+ }
const TString &structName = StructNameString(*node->getType().getStruct());
mStructureHLSL->addConstructor(node->getType(), structName, node->getSequence());
- outputTriplet(visit, (structName + "_ctor(").c_str(), ", ", ")");
+ outputTriplet(out, visit, (structName + "_ctor(").c_str(), ", ", ")");
}
break;
- case EOpLessThan: outputTriplet(visit, "(", " < ", ")"); break;
- case EOpGreaterThan: outputTriplet(visit, "(", " > ", ")"); break;
- case EOpLessThanEqual: outputTriplet(visit, "(", " <= ", ")"); break;
- case EOpGreaterThanEqual: outputTriplet(visit, "(", " >= ", ")"); break;
- case EOpVectorEqual: outputTriplet(visit, "(", " == ", ")"); break;
- case EOpVectorNotEqual: outputTriplet(visit, "(", " != ", ")"); break;
+ case EOpLessThan:
+ outputTriplet(out, visit, "(", " < ", ")");
+ break;
+ case EOpGreaterThan:
+ outputTriplet(out, visit, "(", " > ", ")");
+ break;
+ case EOpLessThanEqual:
+ outputTriplet(out, visit, "(", " <= ", ")");
+ break;
+ case EOpGreaterThanEqual:
+ outputTriplet(out, visit, "(", " >= ", ")");
+ break;
+ case EOpVectorEqual:
+ outputTriplet(out, visit, "(", " == ", ")");
+ break;
+ case EOpVectorNotEqual:
+ outputTriplet(out, visit, "(", " != ", ")");
+ break;
case EOpMod:
ASSERT(node->getUseEmulatedFunction());
- writeEmulatedFunctionTriplet(visit, "mod(");
+ writeEmulatedFunctionTriplet(out, visit, "mod(");
break;
- case EOpModf: outputTriplet(visit, "modf(", ", ", ")"); break;
- case EOpPow: outputTriplet(visit, "pow(", ", ", ")"); break;
+ case EOpModf:
+ outputTriplet(out, visit, "modf(", ", ", ")");
+ break;
+ case EOpPow:
+ outputTriplet(out, visit, "pow(", ", ", ")");
+ break;
case EOpAtan:
ASSERT(node->getSequence()->size() == 2); // atan(x) is a unary operator
ASSERT(node->getUseEmulatedFunction());
- writeEmulatedFunctionTriplet(visit, "atan(");
+ writeEmulatedFunctionTriplet(out, visit, "atan(");
+ break;
+ case EOpMin:
+ outputTriplet(out, visit, "min(", ", ", ")");
+ break;
+ case EOpMax:
+ outputTriplet(out, visit, "max(", ", ", ")");
+ break;
+ case EOpClamp:
+ outputTriplet(out, visit, "clamp(", ", ", ")");
+ break;
+ case EOpMix:
+ {
+ TIntermTyped *lastParamNode = (*(node->getSequence()))[2]->getAsTyped();
+ if (lastParamNode->getType().getBasicType() == EbtBool)
+ {
+ // There is no HLSL equivalent for ESSL3 built-in "genType mix (genType x, genType y, genBType a)",
+ // so use emulated version.
+ ASSERT(node->getUseEmulatedFunction());
+ writeEmulatedFunctionTriplet(out, visit, "mix(");
+ }
+ else
+ {
+ outputTriplet(out, visit, "lerp(", ", ", ")");
+ }
+ }
break;
- case EOpMin: outputTriplet(visit, "min(", ", ", ")"); break;
- case EOpMax: outputTriplet(visit, "max(", ", ", ")"); break;
- case EOpClamp: outputTriplet(visit, "clamp(", ", ", ")"); break;
- case EOpMix: outputTriplet(visit, "lerp(", ", ", ")"); break;
- case EOpStep: outputTriplet(visit, "step(", ", ", ")"); break;
- case EOpSmoothStep: outputTriplet(visit, "smoothstep(", ", ", ")"); break;
- case EOpDistance: outputTriplet(visit, "distance(", ", ", ")"); break;
- case EOpDot: outputTriplet(visit, "dot(", ", ", ")"); break;
- case EOpCross: outputTriplet(visit, "cross(", ", ", ")"); break;
+ case EOpStep:
+ outputTriplet(out, visit, "step(", ", ", ")");
+ break;
+ case EOpSmoothStep:
+ outputTriplet(out, visit, "smoothstep(", ", ", ")");
+ break;
+ case EOpDistance:
+ outputTriplet(out, visit, "distance(", ", ", ")");
+ break;
+ case EOpDot:
+ outputTriplet(out, visit, "dot(", ", ", ")");
+ break;
+ case EOpCross:
+ outputTriplet(out, visit, "cross(", ", ", ")");
+ break;
case EOpFaceForward:
ASSERT(node->getUseEmulatedFunction());
- writeEmulatedFunctionTriplet(visit, "faceforward(");
+ writeEmulatedFunctionTriplet(out, visit, "faceforward(");
break;
- case EOpReflect: outputTriplet(visit, "reflect(", ", ", ")"); break;
- case EOpRefract: outputTriplet(visit, "refract(", ", ", ")"); break;
+ case EOpReflect:
+ outputTriplet(out, visit, "reflect(", ", ", ")");
+ break;
+ case EOpRefract:
+ outputTriplet(out, visit, "refract(", ", ", ")");
+ break;
case EOpOuterProduct:
ASSERT(node->getUseEmulatedFunction());
- writeEmulatedFunctionTriplet(visit, "outerProduct(");
+ writeEmulatedFunctionTriplet(out, visit, "outerProduct(");
break;
- case EOpMul: outputTriplet(visit, "(", " * ", ")"); break;
+ case EOpMul:
+ outputTriplet(out, visit, "(", " * ", ")");
+ break;
default: UNREACHABLE();
}
return true;
}
-bool OutputHLSL::visitSelection(Visit visit, TIntermSelection *node)
+void OutputHLSL::writeSelection(TInfoSinkBase &out, TIntermSelection *node)
{
- TInfoSinkBase &out = getInfoSink();
+ out << "if (";
- if (node->usesTernaryOperator())
- {
- out << "s" << mUnfoldShortCircuit->getNextTemporaryIndex();
- }
- else // if/else statement
- {
- mUnfoldShortCircuit->traverse(node->getCondition());
+ node->getCondition()->traverse(this);
- // D3D errors when there is a gradient operation in a loop in an unflattened if
- // however flattening all the ifs in branch heavy shaders made D3D error too.
- // As a temporary workaround we flatten the ifs only if there is at least a loop
- // present somewhere in the shader.
- if (mShaderType == GL_FRAGMENT_SHADER && mContainsAnyLoop)
- {
- out << "FLATTEN ";
- }
+ out << ")\n";
- out << "if (";
+ outputLineDirective(out, node->getLine().first_line);
- node->getCondition()->traverse(this);
+ bool discard = false;
- out << ")\n";
+ if (node->getTrueBlock())
+ {
+ // The trueBlock child node will output braces.
+ ASSERT(IsSequence(node->getTrueBlock()));
- outputLineDirective(node->getLine().first_line);
- out << "{\n";
+ node->getTrueBlock()->traverse(this);
- bool discard = false;
+ // Detect true discard
+ discard = (discard || FindDiscard::search(node->getTrueBlock()));
+ }
+ else
+ {
+ // TODO(oetuaho): Check if the semicolon inside is necessary.
+ // It's there as a result of conservative refactoring of the output.
+ out << "{;}\n";
+ }
- if (node->getTrueBlock())
- {
- traverseStatements(node->getTrueBlock());
+ outputLineDirective(out, node->getLine().first_line);
- // Detect true discard
- discard = (discard || FindDiscard::search(node->getTrueBlock()));
- }
+ if (node->getFalseBlock())
+ {
+ out << "else\n";
- outputLineDirective(node->getLine().first_line);
- out << ";\n}\n";
+ outputLineDirective(out, node->getFalseBlock()->getLine().first_line);
- if (node->getFalseBlock())
- {
- out << "else\n";
+ // Either this is "else if" or the falseBlock child node will output braces.
+ ASSERT(IsSequence(node->getFalseBlock()) || node->getFalseBlock()->getAsSelectionNode() != nullptr);
- outputLineDirective(node->getFalseBlock()->getLine().first_line);
- out << "{\n";
+ node->getFalseBlock()->traverse(this);
- outputLineDirective(node->getFalseBlock()->getLine().first_line);
- traverseStatements(node->getFalseBlock());
+ outputLineDirective(out, node->getFalseBlock()->getLine().first_line);
- outputLineDirective(node->getFalseBlock()->getLine().first_line);
- out << ";\n}\n";
+ // Detect false discard
+ discard = (discard || FindDiscard::search(node->getFalseBlock()));
+ }
- // Detect false discard
- discard = (discard || FindDiscard::search(node->getFalseBlock()));
- }
+ // ANGLE issue 486: Detect problematic conditional discard
+ if (discard)
+ {
+ mUsesDiscardRewriting = true;
+ }
+}
- // ANGLE issue 486: Detect problematic conditional discard
- if (discard && FindSideEffectRewriting::search(node))
- {
- mUsesDiscardRewriting = true;
- }
+bool OutputHLSL::visitSelection(Visit visit, TIntermSelection *node)
+{
+ TInfoSinkBase &out = getInfoSink();
+
+ ASSERT(!node->usesTernaryOperator());
+
+ if (!mInsideFunction)
+ {
+ // This is part of unfolded global initialization.
+ mDeferredGlobalInitializers.push_back(node);
+ return false;
}
+ // D3D errors when there is a gradient operation in a loop in an unflattened if.
+ if (mShaderType == GL_FRAGMENT_SHADER && mCurrentFunctionMetadata->hasGradientLoop(node))
+ {
+ out << "FLATTEN ";
+ }
+
+ writeSelection(out, node);
+
return false;
}
bool OutputHLSL::visitSwitch(Visit visit, TIntermSwitch *node)
{
+ TInfoSinkBase &out = getInfoSink();
+
if (node->getStatementList())
{
node->setStatementList(RemoveSwitchFallThrough::removeFallThrough(node->getStatementList()));
- outputTriplet(visit, "switch (", ") ", "");
+ outputTriplet(out, visit, "switch (", ") ", "");
// The curly braces get written when visiting the statementList aggregate
}
else
{
// No statementList, so it won't output curly braces
- outputTriplet(visit, "switch (", ") {", "}\n");
+ outputTriplet(out, visit, "switch (", ") {", "}\n");
}
return true;
}
bool OutputHLSL::visitCase(Visit visit, TIntermCase *node)
{
+ TInfoSinkBase &out = getInfoSink();
+
if (node->hasCondition())
{
- outputTriplet(visit, "case (", "", "):\n");
+ outputTriplet(out, visit, "case (", "", "):\n");
return true;
}
else
{
- TInfoSinkBase &out = getInfoSink();
out << "default:\n";
return false;
}
@@ -2354,7 +2780,8 @@ bool OutputHLSL::visitCase(Visit visit, TIntermCase *node)
void OutputHLSL::visitConstantUnion(TIntermConstantUnion *node)
{
- writeConstantUnion(node->getType(), node->getUnionArrayPointer());
+ TInfoSinkBase &out = getInfoSink();
+ writeConstantUnion(out, node->getType(), node->getUnionArrayPointer());
}
bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node)
@@ -2362,15 +2789,14 @@ bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node)
mNestedLoopDepth++;
bool wasDiscontinuous = mInsideDiscontinuousLoop;
+ mInsideDiscontinuousLoop = mInsideDiscontinuousLoop ||
+ mCurrentFunctionMetadata->mDiscontinuousLoops.count(node) > 0;
- if (mContainsLoopDiscontinuity && !mInsideDiscontinuousLoop)
- {
- mInsideDiscontinuousLoop = containsLoopDiscontinuity(node);
- }
+ TInfoSinkBase &out = getInfoSink();
- if (mOutputType == SH_HLSL9_OUTPUT)
+ if (mOutputType == SH_HLSL_3_0_OUTPUT)
{
- if (handleExcessiveLoop(node))
+ if (handleExcessiveLoop(out, node))
{
mInsideDiscontinuousLoop = wasDiscontinuous;
mNestedLoopDepth--;
@@ -2379,18 +2805,16 @@ bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node)
}
}
- TInfoSinkBase &out = getInfoSink();
-
+ const char *unroll = mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : "";
if (node->getType() == ELoopDoWhile)
{
- out << "{LOOP do\n";
+ out << "{" << unroll << " do\n";
- outputLineDirective(node->getLine().first_line);
- out << "{\n";
+ outputLineDirective(out, node->getLine().first_line);
}
else
{
- out << "{LOOP for(";
+ out << "{" << unroll << " for(";
if (node->getInit())
{
@@ -2413,21 +2837,27 @@ bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node)
out << ")\n";
- outputLineDirective(node->getLine().first_line);
- out << "{\n";
+ outputLineDirective(out, node->getLine().first_line);
}
if (node->getBody())
{
- traverseStatements(node->getBody());
+ // The loop body node will output braces.
+ ASSERT(IsSequence(node->getBody()));
+ node->getBody()->traverse(this);
+ }
+ else
+ {
+ // TODO(oetuaho): Check if the semicolon inside is necessary.
+ // It's there as a result of conservative refactoring of the output.
+ out << "{;}\n";
}
- outputLineDirective(node->getLine().first_line);
- out << ";}\n";
+ outputLineDirective(out, node->getLine().first_line);
if (node->getType() == ELoopDoWhile)
{
- outputLineDirective(node->getCondition()->getLine().first_line);
+ outputLineDirective(out, node->getCondition()->getLine().first_line);
out << "while(\n";
node->getCondition()->traverse(this);
@@ -2450,7 +2880,7 @@ bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node)
switch (node->getFlowOp())
{
case EOpKill:
- outputTriplet(visit, "discard;\n", "", "");
+ outputTriplet(out, visit, "discard;\n", "", "");
break;
case EOpBreak:
if (visit == PreVisit)
@@ -2472,7 +2902,9 @@ bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node)
}
}
break;
- case EOpContinue: outputTriplet(visit, "continue;\n", "", ""); break;
+ case EOpContinue:
+ outputTriplet(out, visit, "continue;\n", "", "");
+ break;
case EOpReturn:
if (visit == PreVisit)
{
@@ -2499,16 +2931,6 @@ bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node)
return true;
}
-void OutputHLSL::traverseStatements(TIntermNode *node)
-{
- if (isSingleStatement(node))
- {
- mUnfoldShortCircuit->traverse(node);
- }
-
- node->traverse(this);
-}
-
bool OutputHLSL::isSingleStatement(TIntermNode *node)
{
TIntermAggregate *aggregate = node->getAsAggregate();
@@ -2544,10 +2966,9 @@ bool OutputHLSL::isSingleStatement(TIntermNode *node)
// Handle loops with more than 254 iterations (unsupported by D3D9) by splitting them
// (The D3D documentation says 255 iterations, but the compiler complains at anything more than 254).
-bool OutputHLSL::handleExcessiveLoop(TIntermLoop *node)
+bool OutputHLSL::handleExcessiveLoop(TInfoSinkBase &out, TIntermLoop *node)
{
const int MAX_LOOP_ITERATIONS = 254;
- TInfoSinkBase &out = getInfoSink();
// Parse loops of the form:
// for(int index = initial; index [comparator] limit; index += increment)
@@ -2696,8 +3117,9 @@ bool OutputHLSL::handleExcessiveLoop(TIntermLoop *node)
}
// for(int index = initial; index < clampedLimit; index += increment)
+ const char *unroll = mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : "";
- out << "LOOP for(";
+ out << unroll << " for(";
index->traverse(this);
out << " = ";
out << initial;
@@ -2713,7 +3135,7 @@ bool OutputHLSL::handleExcessiveLoop(TIntermLoop *node)
out << increment;
out << ")\n";
- outputLineDirective(node->getLine().first_line);
+ outputLineDirective(out, node->getLine().first_line);
out << "{\n";
if (node->getBody())
@@ -2721,7 +3143,7 @@ bool OutputHLSL::handleExcessiveLoop(TIntermLoop *node)
node->getBody()->traverse(this);
}
- outputLineDirective(node->getLine().first_line);
+ outputLineDirective(out, node->getLine().first_line);
out << ";}\n";
if (!firstLoopFragment)
@@ -2747,7 +3169,11 @@ bool OutputHLSL::handleExcessiveLoop(TIntermLoop *node)
return false; // Not handled as an excessive loop
}
-void OutputHLSL::outputTriplet(Visit visit, const char *preString, const char *inString, const char *postString, TInfoSinkBase &out)
+void OutputHLSL::outputTriplet(TInfoSinkBase &out,
+ Visit visit,
+ const char *preString,
+ const char *inString,
+ const char *postString)
{
if (visit == PreVisit)
{
@@ -2763,17 +3189,10 @@ void OutputHLSL::outputTriplet(Visit visit, const char *preString, const char *i
}
}
-void OutputHLSL::outputTriplet(Visit visit, const char *preString, const char *inString, const char *postString)
-{
- outputTriplet(visit, preString, inString, postString, getInfoSink());
-}
-
-void OutputHLSL::outputLineDirective(int line)
+void OutputHLSL::outputLineDirective(TInfoSinkBase &out, int line)
{
if ((mCompileOptions & SH_LINE_DIRECTIVES) && (line > 0))
{
- TInfoSinkBase &out = getInfoSink();
-
out << "\n";
out << "#line " << line;
@@ -2789,25 +3208,37 @@ void OutputHLSL::outputLineDirective(int line)
TString OutputHLSL::argumentString(const TIntermSymbol *symbol)
{
TQualifier qualifier = symbol->getQualifier();
- const TType &type = symbol->getType();
- TString name = symbol->getSymbol();
+ const TType &type = symbol->getType();
+ const TName &name = symbol->getName();
+ TString nameStr;
- if (name.empty()) // HLSL demands named arguments, also for prototypes
+ if (name.getString().empty()) // HLSL demands named arguments, also for prototypes
{
- name = "x" + str(mUniqueIndex++);
+ nameStr = "x" + str(mUniqueIndex++);
}
else
{
- name = Decorate(name);
+ nameStr = DecorateIfNeeded(name);
}
- if (mOutputType == SH_HLSL11_OUTPUT && IsSampler(type.getBasicType()))
+ if (IsSampler(type.getBasicType()))
{
- return QualifierString(qualifier) + " " + TextureString(type) + " texture_" + name + ArrayString(type) + ", " +
- QualifierString(qualifier) + " " + SamplerString(type) + " sampler_" + name + ArrayString(type);
+ if (mOutputType == SH_HLSL_4_1_OUTPUT)
+ {
+ // Samplers are passed as indices to the sampler array.
+ ASSERT(qualifier != EvqOut && qualifier != EvqInOut);
+ return "const uint " + nameStr + ArrayString(type);
+ }
+ if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
+ {
+ return QualifierString(qualifier) + " " + TextureString(type.getBasicType()) +
+ " texture_" + nameStr + ArrayString(type) + ", " + QualifierString(qualifier) +
+ " " + SamplerString(type.getBasicType()) + " sampler_" + nameStr +
+ ArrayString(type);
+ }
}
- return QualifierString(qualifier) + " " + TypeString(type) + " " + name + ArrayString(type);
+ return QualifierString(qualifier) + " " + TypeString(type) + " " + nameStr + ArrayString(type);
}
TString OutputHLSL::initializer(const TType &type)
@@ -2828,9 +3259,16 @@ TString OutputHLSL::initializer(const TType &type)
return "{" + string + "}";
}
-void OutputHLSL::outputConstructor(Visit visit, const TType &type, const char *name, const TIntermSequence *parameters)
+void OutputHLSL::outputConstructor(TInfoSinkBase &out,
+ Visit visit,
+ const TType &type,
+ const char *name,
+ const TIntermSequence *parameters)
{
- TInfoSinkBase &out = getInfoSink();
+ if (type.isArray())
+ {
+ UNIMPLEMENTED();
+ }
if (visit == PreVisit)
{
@@ -2848,9 +3286,11 @@ void OutputHLSL::outputConstructor(Visit visit, const TType &type, const char *n
}
}
-const ConstantUnion *OutputHLSL::writeConstantUnion(const TType &type, const ConstantUnion *constUnion)
+const TConstantUnion *OutputHLSL::writeConstantUnion(TInfoSinkBase &out,
+ const TType &type,
+ const TConstantUnion *const constUnion)
{
- TInfoSinkBase &out = getInfoSink();
+ const TConstantUnion *constUnionIterated = constUnion;
const TStructure* structure = type.getStruct();
if (structure)
@@ -2862,7 +3302,7 @@ const ConstantUnion *OutputHLSL::writeConstantUnion(const TType &type, const Con
for (size_t i = 0; i < fields.size(); i++)
{
const TType *fieldType = fields[i]->type();
- constUnion = writeConstantUnion(*fieldType, constUnion);
+ constUnionIterated = writeConstantUnion(out, *fieldType, constUnionIterated);
if (i != fields.size() - 1)
{
@@ -2881,37 +3321,20 @@ const ConstantUnion *OutputHLSL::writeConstantUnion(const TType &type, const Con
{
out << TypeString(type) << "(";
}
-
- for (size_t i = 0; i < size; i++, constUnion++)
- {
- 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();
- }
-
- if (i != size - 1)
- {
- out << ", ";
- }
- }
-
+ constUnionIterated = WriteConstantUnionArray(out, constUnionIterated, size);
if (writeType)
{
out << ")";
}
}
- return constUnion;
+ return constUnionIterated;
}
-void OutputHLSL::writeEmulatedFunctionTriplet(Visit visit, const char *preStr)
+void OutputHLSL::writeEmulatedFunctionTriplet(TInfoSinkBase &out, Visit visit, const char *preStr)
{
TString preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preStr);
- outputTriplet(visit, preString.c_str(), ", ", ")");
+ outputTriplet(out, visit, preString.c_str(), ", ", ")");
}
bool OutputHLSL::writeSameSymbolInitializer(TInfoSinkBase &out, TIntermSymbol *symbolNode, TIntermTyped *expression)
@@ -2935,6 +3358,68 @@ bool OutputHLSL::writeSameSymbolInitializer(TInfoSinkBase &out, TIntermSymbol *s
return false;
}
+bool OutputHLSL::canWriteAsHLSLLiteral(TIntermTyped *expression)
+{
+ // We support writing constant unions and constructors that only take constant unions as
+ // parameters as HLSL literals.
+ if (expression->getAsConstantUnion())
+ {
+ return true;
+ }
+ if (expression->getQualifier() != EvqConst || !expression->getAsAggregate() ||
+ !expression->getAsAggregate()->isConstructor())
+ {
+ return false;
+ }
+ TIntermAggregate *constructor = expression->getAsAggregate();
+ for (TIntermNode *&node : *constructor->getSequence())
+ {
+ if (!node->getAsConstantUnion())
+ return false;
+ }
+ return true;
+}
+
+bool OutputHLSL::writeConstantInitialization(TInfoSinkBase &out,
+ TIntermSymbol *symbolNode,
+ TIntermTyped *expression)
+{
+ if (canWriteAsHLSLLiteral(expression))
+ {
+ symbolNode->traverse(this);
+ if (expression->getType().isArray())
+ {
+ out << "[" << expression->getType().getArraySize() << "]";
+ }
+ out << " = {";
+ if (expression->getAsConstantUnion())
+ {
+ TIntermConstantUnion *nodeConst = expression->getAsConstantUnion();
+ const TConstantUnion *constUnion = nodeConst->getUnionArrayPointer();
+ WriteConstantUnionArray(out, constUnion, nodeConst->getType().getObjectSize());
+ }
+ else
+ {
+ TIntermAggregate *constructor = expression->getAsAggregate();
+ ASSERT(constructor != nullptr);
+ for (TIntermNode *&node : *constructor->getSequence())
+ {
+ TIntermConstantUnion *nodeConst = node->getAsConstantUnion();
+ ASSERT(nodeConst);
+ const TConstantUnion *constUnion = nodeConst->getUnionArrayPointer();
+ WriteConstantUnionArray(out, constUnion, nodeConst->getType().getObjectSize());
+ if (node != constructor->getSequence()->back())
+ {
+ out << ", ";
+ }
+ }
+ }
+ out << "}";
+ return true;
+ }
+ return false;
+}
+
void OutputHLSL::writeDeferredGlobalInitializers(TInfoSinkBase &out)
{
out << "#define ANGLE_USES_DEFERRED_INIT\n"
@@ -2942,23 +3427,34 @@ void OutputHLSL::writeDeferredGlobalInitializers(TInfoSinkBase &out)
<< "void initializeDeferredGlobals()\n"
<< "{\n";
- for (auto it = mDeferredGlobalInitializers.cbegin(); it != mDeferredGlobalInitializers.cend(); ++it)
+ for (const auto &deferredGlobal : mDeferredGlobalInitializers)
{
- const auto &deferredGlobal = *it;
- TIntermSymbol *symbol = deferredGlobal.first;
- TIntermTyped *expression = deferredGlobal.second;
- ASSERT(symbol);
- ASSERT(symbol->getQualifier() == EvqGlobal && expression->getQualifier() != EvqConst);
+ TIntermBinary *binary = deferredGlobal->getAsBinaryNode();
+ TIntermSelection *selection = deferredGlobal->getAsSelectionNode();
+ if (binary != nullptr)
+ {
+ TIntermSymbol *symbol = binary->getLeft()->getAsSymbolNode();
+ TIntermTyped *expression = binary->getRight();
+ ASSERT(symbol);
+ ASSERT(symbol->getQualifier() == EvqGlobal && expression->getQualifier() != EvqConst);
- out << " " << Decorate(symbol->getSymbol()) << " = ";
+ out << " " << Decorate(symbol->getSymbol()) << " = ";
- if (!writeSameSymbolInitializer(out, symbol, expression))
+ if (!writeSameSymbolInitializer(out, symbol, expression))
+ {
+ ASSERT(mInfoSinkStack.top() == &out);
+ expression->traverse(this);
+ }
+ out << ";\n";
+ }
+ else if (selection != nullptr)
{
- ASSERT(mInfoSinkStack.top() == &out);
- expression->traverse(this);
+ writeSelection(out, selection);
+ }
+ else
+ {
+ UNREACHABLE();
}
-
- out << ";\n";
}
out << "}\n"
@@ -2969,9 +3465,8 @@ TString OutputHLSL::addStructEqualityFunction(const TStructure &structure)
{
const TFieldList &fields = structure.fields();
- for (auto it = mStructEqualityFunctions.cbegin(); it != mStructEqualityFunctions.cend(); ++it)
+ for (const auto &eqFunction : mStructEqualityFunctions)
{
- auto *eqFunction = *it;
if (eqFunction->structure == &structure)
{
return eqFunction->functionName;
@@ -3024,9 +3519,8 @@ TString OutputHLSL::addStructEqualityFunction(const TStructure &structure)
TString OutputHLSL::addArrayEqualityFunction(const TType& type)
{
- for (auto it = mArrayEqualityFunctions.cbegin(); it != mArrayEqualityFunctions.cend(); ++it)
+ for (const auto &eqFunction : mArrayEqualityFunctions)
{
- const auto &eqFunction = *it;
if (eqFunction->type == type)
{
return eqFunction->functionName;
@@ -3076,9 +3570,8 @@ TString OutputHLSL::addArrayEqualityFunction(const TType& type)
TString OutputHLSL::addArrayAssignmentFunction(const TType& type)
{
- for (auto it = mArrayAssignmentFunctions.cbegin(); it != mArrayAssignmentFunctions.cend(); ++it)
+ for (const auto &assignFunction : mArrayAssignmentFunctions)
{
- const auto &assignFunction = *it;
if (assignFunction.type == type)
{
return assignFunction.functionName;
@@ -3113,4 +3606,59 @@ TString OutputHLSL::addArrayAssignmentFunction(const TType& type)
return function.functionName;
}
+TString OutputHLSL::addArrayConstructIntoFunction(const TType& type)
+{
+ for (const auto &constructIntoFunction : mArrayConstructIntoFunctions)
+ {
+ if (constructIntoFunction.type == type)
+ {
+ return constructIntoFunction.functionName;
+ }
+ }
+
+ const TString &typeName = TypeString(type);
+
+ ArrayHelperFunction function;
+ function.type = type;
+
+ TInfoSinkBase fnNameOut;
+ fnNameOut << "angle_construct_into_" << type.getArraySize() << "_" << typeName;
+ function.functionName = fnNameOut.c_str();
+
+ TInfoSinkBase fnOut;
+
+ fnOut << "void " << function.functionName << "(out "
+ << typeName << " a[" << type.getArraySize() << "]";
+ for (int i = 0; i < type.getArraySize(); ++i)
+ {
+ fnOut << ", " << typeName << " b" << i;
+ }
+ fnOut << ")\n"
+ "{\n";
+
+ for (int i = 0; i < type.getArraySize(); ++i)
+ {
+ fnOut << " a[" << i << "] = b" << i << ";\n";
+ }
+ fnOut << "}\n";
+
+ function.functionDefinition = fnOut.c_str();
+
+ mArrayConstructIntoFunctions.push_back(function);
+
+ return function.functionName;
+}
+
+void OutputHLSL::ensureStructDefined(const TType &type)
+{
+ TStructure *structure = type.getStruct();
+
+ if (structure)
+ {
+ mStructureHLSL->addConstructor(type, StructNameString(*structure), nullptr);
+ }
+}
+
+
+
}
diff --git a/src/3rdparty/angle/src/compiler/translator/OutputHLSL.h b/src/3rdparty/angle/src/compiler/translator/OutputHLSL.h
index 51da877c72..8756d0ba4c 100644
--- a/src/3rdparty/angle/src/compiler/translator/OutputHLSL.h
+++ b/src/3rdparty/angle/src/compiler/translator/OutputHLSL.h
@@ -13,6 +13,7 @@
#include <stack>
#include "angle_gl.h"
+#include "compiler/translator/ASTMetadataHLSL.h"
#include "compiler/translator/IntermNode.h"
#include "compiler/translator/ParseContext.h"
@@ -46,8 +47,10 @@ class OutputHLSL : public TIntermTraverser
TInfoSinkBase &getInfoSink() { ASSERT(!mInfoSinkStack.empty()); return *mInfoSinkStack.top(); }
+ static bool canWriteAsHLSLLiteral(TIntermTyped *expression);
+
protected:
- void header(const BuiltInFunctionEmulator *builtInFunctionEmulator);
+ void header(TInfoSinkBase &out, const BuiltInFunctionEmulator *builtInFunctionEmulator);
// Visit AST nodes and output their code to the body stream
void visitSymbol(TIntermSymbol*);
@@ -62,34 +65,52 @@ class OutputHLSL : public TIntermTraverser
bool visitLoop(Visit visit, TIntermLoop*);
bool visitBranch(Visit visit, TIntermBranch*);
- void traverseStatements(TIntermNode *node);
bool isSingleStatement(TIntermNode *node);
- bool handleExcessiveLoop(TIntermLoop *node);
+ bool handleExcessiveLoop(TInfoSinkBase &out, TIntermLoop *node);
// Emit one of three strings depending on traverse phase. Called with literal strings so using const char* instead of TString.
- void outputTriplet(Visit visit, const char *preString, const char *inString, const char *postString, TInfoSinkBase &out);
- void outputTriplet(Visit visit, const char *preString, const char *inString, const char *postString);
- void outputLineDirective(int line);
+ void outputTriplet(TInfoSinkBase &out,
+ Visit visit,
+ const char *preString,
+ const char *inString,
+ const char *postString);
+ void outputLineDirective(TInfoSinkBase &out, int line);
TString argumentString(const TIntermSymbol *symbol);
int vectorSize(const TType &type) const;
// Emit constructor. Called with literal names so using const char* instead of TString.
- void outputConstructor(Visit visit, const TType &type, const char *name, const TIntermSequence *parameters);
- const ConstantUnion *writeConstantUnion(const TType &type, const ConstantUnion *constUnion);
+ void outputConstructor(TInfoSinkBase &out,
+ Visit visit,
+ const TType &type,
+ const char *name,
+ const TIntermSequence *parameters);
+ const TConstantUnion *writeConstantUnion(TInfoSinkBase &out,
+ const TType &type,
+ const TConstantUnion *constUnion);
void outputEqual(Visit visit, const TType &type, TOperator op, TInfoSinkBase &out);
- void writeEmulatedFunctionTriplet(Visit visit, const char *preStr);
+ void writeEmulatedFunctionTriplet(TInfoSinkBase &out, Visit visit, const char *preStr);
void makeFlaggedStructMaps(const std::vector<TIntermTyped *> &flaggedStructs);
// Returns true if it found a 'same symbol' initializer (initializer that references the variable it's initting)
bool writeSameSymbolInitializer(TInfoSinkBase &out, TIntermSymbol *symbolNode, TIntermTyped *expression);
+ // Returns true if variable initializer could be written using literal {} notation.
+ bool writeConstantInitialization(TInfoSinkBase &out,
+ TIntermSymbol *symbolNode,
+ TIntermTyped *expression);
+
void writeDeferredGlobalInitializers(TInfoSinkBase &out);
+ void writeSelection(TInfoSinkBase &out, TIntermSelection *node);
// Returns the function name
TString addStructEqualityFunction(const TStructure &structure);
TString addArrayEqualityFunction(const TType &type);
TString addArrayAssignmentFunction(const TType &type);
+ TString addArrayConstructIntoFunction(const TType &type);
+
+ // Ensures if the type is a struct, the struct is defined
+ void ensureStructDefined(const TType &type);
sh::GLenum mShaderType;
int mShaderVersion;
@@ -98,7 +119,6 @@ class OutputHLSL : public TIntermTraverser
const ShShaderOutput mOutputType;
int mCompileOptions;
- UnfoldShortCircuit *mUnfoldShortCircuit;
bool mInsideFunction;
// Output streams
@@ -168,8 +188,9 @@ class OutputHLSL : public TIntermTraverser
int mUniqueIndex; // For creating unique names
- bool mContainsLoopDiscontinuity;
- bool mContainsAnyLoop;
+ CallDAG mCallDag;
+ MetadataList mASTMetadataList;
+ ASTMetadataHLSL *mCurrentFunctionMetadata;
bool mOutputLod0Function;
bool mInsideDiscontinuousLoop;
int mNestedLoopDepth;
@@ -181,11 +202,10 @@ class OutputHLSL : public TIntermTraverser
std::map<TIntermTyped*, TString> mFlaggedStructMappedNames;
std::map<TIntermTyped*, TString> mFlaggedStructOriginalNames;
- // Some initializers use varyings, uniforms or attributes, thus we can't evaluate some variables
- // at global static scope in HLSL. These variables depend on values which we retrieve from the
- // shader input structure, which we set in the D3D main function. Instead, we can initialize
- // these static globals after we initialize our other globals.
- std::vector<std::pair<TIntermSymbol*, TIntermTyped*>> mDeferredGlobalInitializers;
+ // Some initializers may have been unfolded into if statements, thus we can't evaluate all initializers
+ // at global static scope in HLSL. Instead, we can initialize these static globals inside a helper function.
+ // This also enables initialization of globals with uniforms.
+ TIntermSequence mDeferredGlobalInitializers;
struct HelperFunction
{
@@ -214,6 +234,11 @@ class OutputHLSL : public TIntermTraverser
std::vector<ArrayHelperFunction*> mArrayEqualityFunctions;
std::vector<ArrayHelperFunction> mArrayAssignmentFunctions;
+
+ // The construct-into functions are functions that fill an N-element array passed as an out parameter
+ // with the other N parameters of the function. This is used to work around that arrays can't be
+ // return values in HLSL.
+ std::vector<ArrayHelperFunction> mArrayConstructIntoFunctions;
};
}
diff --git a/src/3rdparty/angle/src/compiler/translator/ParseContext.cpp b/src/3rdparty/angle/src/compiler/translator/ParseContext.cpp
index 7ad3f817ad..235351cf41 100644
--- a/src/3rdparty/angle/src/compiler/translator/ParseContext.cpp
+++ b/src/3rdparty/angle/src/compiler/translator/ParseContext.cpp
@@ -10,8 +10,11 @@
#include <stdio.h>
#include "compiler/preprocessor/SourceLocation.h"
+#include "compiler/translator/Cache.h"
#include "compiler/translator/glslang.h"
#include "compiler/translator/ValidateSwitch.h"
+#include "compiler/translator/ValidateGlobalInitializer.h"
+#include "compiler/translator/util.h"
///////////////////////////////////////////////////////////////////////
//
@@ -23,86 +26,98 @@
// Look at a '.' field selector string and change it into offsets
// for a vector.
//
-bool TParseContext::parseVectorFields(const TString& compString, int vecSize, TVectorFields& fields, const TSourceLoc& line)
+bool TParseContext::parseVectorFields(const TString &compString,
+ int vecSize,
+ TVectorFields &fields,
+ const TSourceLoc &line)
{
- fields.num = (int) compString.size();
- if (fields.num > 4) {
+ fields.num = (int)compString.size();
+ if (fields.num > 4)
+ {
error(line, "illegal vector field selection", compString.c_str());
return false;
}
- enum {
+ enum
+ {
exyzw,
ergba,
estpq
} fieldSet[4];
- for (int i = 0; i < fields.num; ++i) {
- switch (compString[i]) {
- case 'x':
- fields.offsets[i] = 0;
- fieldSet[i] = exyzw;
- break;
- case 'r':
- fields.offsets[i] = 0;
- fieldSet[i] = ergba;
- break;
- case 's':
- fields.offsets[i] = 0;
- fieldSet[i] = estpq;
- break;
- case 'y':
- fields.offsets[i] = 1;
- fieldSet[i] = exyzw;
- break;
- case 'g':
- fields.offsets[i] = 1;
- fieldSet[i] = ergba;
- break;
- case 't':
- fields.offsets[i] = 1;
- fieldSet[i] = estpq;
- break;
- case 'z':
- fields.offsets[i] = 2;
- fieldSet[i] = exyzw;
- break;
- case 'b':
- fields.offsets[i] = 2;
- fieldSet[i] = ergba;
- break;
- case 'p':
- fields.offsets[i] = 2;
- fieldSet[i] = estpq;
- break;
-
- case 'w':
- fields.offsets[i] = 3;
- fieldSet[i] = exyzw;
- break;
- case 'a':
- fields.offsets[i] = 3;
- fieldSet[i] = ergba;
- break;
- case 'q':
- fields.offsets[i] = 3;
- fieldSet[i] = estpq;
- break;
- default:
- error(line, "illegal vector field selection", compString.c_str());
- return false;
+ for (int i = 0; i < fields.num; ++i)
+ {
+ switch (compString[i])
+ {
+ case 'x':
+ fields.offsets[i] = 0;
+ fieldSet[i] = exyzw;
+ break;
+ case 'r':
+ fields.offsets[i] = 0;
+ fieldSet[i] = ergba;
+ break;
+ case 's':
+ fields.offsets[i] = 0;
+ fieldSet[i] = estpq;
+ break;
+ case 'y':
+ fields.offsets[i] = 1;
+ fieldSet[i] = exyzw;
+ break;
+ case 'g':
+ fields.offsets[i] = 1;
+ fieldSet[i] = ergba;
+ break;
+ case 't':
+ fields.offsets[i] = 1;
+ fieldSet[i] = estpq;
+ break;
+ case 'z':
+ fields.offsets[i] = 2;
+ fieldSet[i] = exyzw;
+ break;
+ case 'b':
+ fields.offsets[i] = 2;
+ fieldSet[i] = ergba;
+ break;
+ case 'p':
+ fields.offsets[i] = 2;
+ fieldSet[i] = estpq;
+ break;
+
+ case 'w':
+ fields.offsets[i] = 3;
+ fieldSet[i] = exyzw;
+ break;
+ case 'a':
+ fields.offsets[i] = 3;
+ fieldSet[i] = ergba;
+ break;
+ case 'q':
+ fields.offsets[i] = 3;
+ fieldSet[i] = estpq;
+ break;
+ default:
+ error(line, "illegal vector field selection", compString.c_str());
+ return false;
}
}
- for (int i = 0; i < fields.num; ++i) {
- if (fields.offsets[i] >= vecSize) {
- error(line, "vector field selection out of range", compString.c_str());
+ for (int i = 0; i < fields.num; ++i)
+ {
+ if (fields.offsets[i] >= vecSize)
+ {
+ error(line, "vector field selection out of range", compString.c_str());
return false;
}
- if (i > 0) {
- if (fieldSet[i] != fieldSet[i-1]) {
- error(line, "illegal - vector component fields not from the same set", compString.c_str());
+ if (i > 0)
+ {
+ if (fieldSet[i] != fieldSet[i - 1])
+ {
+ error(line, "illegal - vector component fields not from the same set",
+ compString.c_str());
return false;
}
}
@@ -111,55 +126,6 @@ bool TParseContext::parseVectorFields(const TString& compString, int vecSize, TV
return true;
}
-
-//
-// Look at a '.' field selector string and change it into offsets
-// for a matrix.
-//
-bool TParseContext::parseMatrixFields(const TString& compString, int matCols, int matRows, TMatrixFields& fields, const TSourceLoc& line)
-{
- fields.wholeRow = false;
- fields.wholeCol = false;
- fields.row = -1;
- fields.col = -1;
-
- if (compString.size() != 2) {
- error(line, "illegal length of matrix field selection", compString.c_str());
- return false;
- }
-
- if (compString[0] == '_') {
- if (compString[1] < '0' || compString[1] > '3') {
- error(line, "illegal matrix field selection", compString.c_str());
- return false;
- }
- fields.wholeCol = true;
- fields.col = compString[1] - '0';
- } else if (compString[1] == '_') {
- if (compString[0] < '0' || compString[0] > '3') {
- error(line, "illegal matrix field selection", compString.c_str());
- return false;
- }
- fields.wholeRow = true;
- fields.row = compString[0] - '0';
- } else {
- if (compString[0] < '0' || compString[0] > '3' ||
- compString[1] < '0' || compString[1] > '3') {
- error(line, "illegal matrix field selection", compString.c_str());
- return false;
- }
- fields.row = compString[0] - '0';
- fields.col = compString[1] - '0';
- }
-
- if (fields.row >= matRows || fields.col >= matCols) {
- error(line, "matrix field selection out of range", compString.c_str());
- return false;
- }
-
- return true;
-}
-
///////////////////////////////////////////////////////////////////////
//
// Errors
@@ -176,37 +142,49 @@ void TParseContext::recover()
//
// Used by flex/bison to output all syntax and parsing errors.
//
-void TParseContext::error(const TSourceLoc& loc,
- const char* reason, const char* token,
- const char* extraInfo)
+void TParseContext::error(const TSourceLoc &loc,
+ const char *reason,
+ const char *token,
+ const char *extraInfo)
{
pp::SourceLocation srcLoc;
srcLoc.file = loc.first_file;
srcLoc.line = loc.first_line;
- diagnostics.writeInfo(pp::Diagnostics::PP_ERROR,
- srcLoc, reason, token, extraInfo);
-
+ mDiagnostics.writeInfo(pp::Diagnostics::PP_ERROR, srcLoc, reason, token, extraInfo);
}
-void TParseContext::warning(const TSourceLoc& loc,
- const char* reason, const char* token,
- const char* extraInfo) {
+void TParseContext::warning(const TSourceLoc &loc,
+ const char *reason,
+ const char *token,
+ const char *extraInfo)
+{
pp::SourceLocation srcLoc;
srcLoc.file = loc.first_file;
srcLoc.line = loc.first_line;
- diagnostics.writeInfo(pp::Diagnostics::PP_WARNING,
- srcLoc, reason, token, extraInfo);
+ mDiagnostics.writeInfo(pp::Diagnostics::PP_WARNING, srcLoc, reason, token, extraInfo);
}
-void TParseContext::trace(const char* str)
+void TParseContext::outOfRangeError(bool isError,
+ const TSourceLoc &loc,
+ const char *reason,
+ const char *token,
+ const char *extraInfo)
{
- diagnostics.writeDebug(str);
+ if (isError)
+ {
+ error(loc, reason, token, extraInfo);
+ recover();
+ }
+ else
+ {
+ warning(loc, reason, token, extraInfo);
+ }
}
//
// Same error message for all places assignments don't work.
//
-void TParseContext::assignError(const TSourceLoc& line, const char* op, TString left, TString right)
+void TParseContext::assignError(const TSourceLoc &line, const char *op, TString left, TString right)
{
std::stringstream extraInfoStream;
extraInfoStream << "cannot convert from '" << right << "' to '" << left << "'";
@@ -217,11 +195,11 @@ void TParseContext::assignError(const TSourceLoc& line, const char* op, TString
//
// Same error message for all places unary operations don't work.
//
-void TParseContext::unaryOpError(const TSourceLoc& line, const char* op, TString operand)
+void TParseContext::unaryOpError(const TSourceLoc &line, const char *op, TString operand)
{
std::stringstream extraInfoStream;
- extraInfoStream << "no operation '" << op << "' exists that takes an operand of type " << operand
- << " (or there is no acceptable conversion)";
+ extraInfoStream << "no operation '" << op << "' exists that takes an operand of type "
+ << operand << " (or there is no acceptable conversion)";
std::string extraInfo = extraInfoStream.str();
error(line, " wrong operand type", op, extraInfo.c_str());
}
@@ -229,33 +207,44 @@ void TParseContext::unaryOpError(const TSourceLoc& line, const char* op, TString
//
// Same error message for all binary operations don't work.
//
-void TParseContext::binaryOpError(const TSourceLoc& line, const char* op, TString left, TString right)
+void TParseContext::binaryOpError(const TSourceLoc &line,
+ const char *op,
+ TString left,
+ TString right)
{
std::stringstream extraInfoStream;
- extraInfoStream << "no operation '" << op << "' exists that takes a left-hand operand of type '" << left
- << "' and a right operand of type '" << right << "' (or there is no acceptable conversion)";
+ extraInfoStream << "no operation '" << op << "' exists that takes a left-hand operand of type '"
+ << left << "' and a right operand of type '" << right
+ << "' (or there is no acceptable conversion)";
std::string extraInfo = extraInfoStream.str();
- error(line, " wrong operand types ", op, extraInfo.c_str());
+ error(line, " wrong operand types ", op, extraInfo.c_str());
}
-bool TParseContext::precisionErrorCheck(const TSourceLoc& line, TPrecision precision, TBasicType type){
- if (!checksPrecisionErrors)
+bool TParseContext::precisionErrorCheck(const TSourceLoc &line,
+ TPrecision precision,
+ TBasicType type)
+{
+ if (!mChecksPrecisionErrors)
return false;
- switch( type ){
- case EbtFloat:
- if( precision == EbpUndefined ){
- error( line, "No precision specified for (float)", "" );
- return true;
- }
- break;
- case EbtInt:
- if( precision == EbpUndefined ){
- error( line, "No precision specified (int)", "" );
- return true;
+ if (precision == EbpUndefined)
+ {
+ switch (type)
+ {
+ case EbtFloat:
+ error(line, "No precision specified for (float)", "");
+ return true;
+ case EbtInt:
+ case EbtUInt:
+ UNREACHABLE(); // there's always a predeclared qualifier
+ error(line, "No precision specified (int)", "");
+ return true;
+ default:
+ if (IsSampler(type))
+ {
+ error(line, "No precision specified (sampler)", "");
+ return true;
+ }
}
- break;
- default:
- return false;
}
return false;
}
@@ -266,86 +255,112 @@ bool TParseContext::precisionErrorCheck(const TSourceLoc& line, TPrecision preci
//
// Returns true if the was an error.
//
-bool TParseContext::lValueErrorCheck(const TSourceLoc& line, const char* op, TIntermTyped* node)
+bool TParseContext::lValueErrorCheck(const TSourceLoc &line, const char *op, TIntermTyped *node)
{
- TIntermSymbol* symNode = node->getAsSymbolNode();
- TIntermBinary* binaryNode = node->getAsBinaryNode();
+ TIntermSymbol *symNode = node->getAsSymbolNode();
+ TIntermBinary *binaryNode = node->getAsBinaryNode();
- if (binaryNode) {
+ if (binaryNode)
+ {
bool errorReturn;
- switch(binaryNode->getOp()) {
- case EOpIndexDirect:
- case EOpIndexIndirect:
- case EOpIndexDirectStruct:
- case EOpIndexDirectInterfaceBlock:
- return lValueErrorCheck(line, op, binaryNode->getLeft());
- case EOpVectorSwizzle:
- errorReturn = lValueErrorCheck(line, op, binaryNode->getLeft());
- if (!errorReturn) {
- int offset[4] = {0,0,0,0};
-
- TIntermTyped* rightNode = binaryNode->getRight();
- TIntermAggregate *aggrNode = rightNode->getAsAggregate();
-
- for (TIntermSequence::iterator p = aggrNode->getSequence()->begin();
- p != aggrNode->getSequence()->end(); p++) {
- int value = (*p)->getAsTyped()->getAsConstantUnion()->getIConst(0);
- offset[value]++;
- if (offset[value] > 1) {
- error(line, " l-value of swizzle cannot have duplicate components", op);
-
- return true;
+ switch (binaryNode->getOp())
+ {
+ case EOpIndexDirect:
+ case EOpIndexIndirect:
+ case EOpIndexDirectStruct:
+ case EOpIndexDirectInterfaceBlock:
+ return lValueErrorCheck(line, op, binaryNode->getLeft());
+ case EOpVectorSwizzle:
+ errorReturn = lValueErrorCheck(line, op, binaryNode->getLeft());
+ if (!errorReturn)
+ {
+ int offset[4] = {0, 0, 0, 0};
+
+ TIntermTyped *rightNode = binaryNode->getRight();
+ TIntermAggregate *aggrNode = rightNode->getAsAggregate();
+
+ for (TIntermSequence::iterator p = aggrNode->getSequence()->begin();
+ p != aggrNode->getSequence()->end(); p++)
+ {
+ int value = (*p)->getAsTyped()->getAsConstantUnion()->getIConst(0);
+ offset[value]++;
+ if (offset[value] > 1)
+ {
+ error(line, " l-value of swizzle cannot have duplicate components", op);
+
+ return true;
+ }
}
}
- }
- return errorReturn;
- default:
- break;
+ return errorReturn;
+ default:
+ break;
}
error(line, " l-value required", op);
return true;
}
-
- const char* symbol = 0;
+ const char *symbol = 0;
if (symNode != 0)
symbol = symNode->getSymbol().c_str();
- const char* message = 0;
- switch (node->getQualifier()) {
- case EvqConst: message = "can't modify a const"; break;
- case EvqConstReadOnly: message = "can't modify a const"; break;
- case EvqAttribute: message = "can't modify an attribute"; break;
- case EvqFragmentIn: message = "can't modify an input"; break;
- case EvqVertexIn: message = "can't modify an input"; break;
- case EvqUniform: message = "can't modify a uniform"; break;
- case EvqVaryingIn: message = "can't modify a varying"; break;
- case EvqFragCoord: message = "can't modify gl_FragCoord"; break;
- case EvqFrontFacing: message = "can't modify gl_FrontFacing"; break;
- case EvqPointCoord: message = "can't modify gl_PointCoord"; break;
- default:
-
- //
- // Type that can't be written to?
- //
- if (node->getBasicType() == EbtVoid) {
- message = "can't modify void";
- }
- if (IsSampler(node->getBasicType())) {
- message = "can't modify a sampler";
- }
+ const char *message = 0;
+ switch (node->getQualifier())
+ {
+ case EvqConst:
+ message = "can't modify a const";
+ break;
+ case EvqConstReadOnly:
+ message = "can't modify a const";
+ break;
+ case EvqAttribute:
+ message = "can't modify an attribute";
+ break;
+ case EvqFragmentIn:
+ message = "can't modify an input";
+ break;
+ case EvqVertexIn:
+ message = "can't modify an input";
+ break;
+ case EvqUniform:
+ message = "can't modify a uniform";
+ break;
+ case EvqVaryingIn:
+ message = "can't modify a varying";
+ break;
+ case EvqFragCoord:
+ message = "can't modify gl_FragCoord";
+ break;
+ case EvqFrontFacing:
+ message = "can't modify gl_FrontFacing";
+ break;
+ case EvqPointCoord:
+ message = "can't modify gl_PointCoord";
+ break;
+ default:
+ //
+ // Type that can't be written to?
+ //
+ if (node->getBasicType() == EbtVoid)
+ {
+ message = "can't modify void";
+ }
+ if (IsSampler(node->getBasicType()))
+ {
+ message = "can't modify a sampler";
+ }
}
- if (message == 0 && binaryNode == 0 && symNode == 0) {
+ if (message == 0 && binaryNode == 0 && symNode == 0)
+ {
error(line, " l-value required", op);
return true;
}
-
//
// Everything else is okay, no error.
//
@@ -355,13 +370,15 @@ bool TParseContext::lValueErrorCheck(const TSourceLoc& line, const char* op, TIn
//
// If we get here, we have an error and a message.
//
- if (symNode) {
+ if (symNode)
+ {
std::stringstream extraInfoStream;
extraInfoStream << "\"" << symbol << "\" (" << message << ")";
std::string extraInfo = extraInfoStream.str();
error(line, " l-value required", op, extraInfo.c_str());
}
- else {
+ else
+ {
std::stringstream extraInfoStream;
extraInfoStream << "(" << message << ")";
std::string extraInfo = extraInfoStream.str();
@@ -377,7 +394,7 @@ bool TParseContext::lValueErrorCheck(const TSourceLoc& line, const char* op, TIn
//
// Returns true if the was an error.
//
-bool TParseContext::constErrorCheck(TIntermTyped* node)
+bool TParseContext::constErrorCheck(TIntermTyped *node)
{
if (node->getQualifier() == EvqConst)
return false;
@@ -393,7 +410,7 @@ bool TParseContext::constErrorCheck(TIntermTyped* node)
//
// Returns true if the was an error.
//
-bool TParseContext::integerErrorCheck(TIntermTyped* node, const char* token)
+bool TParseContext::integerErrorCheck(TIntermTyped *node, const char *token)
{
if (node->isScalarInt())
return false;
@@ -409,7 +426,7 @@ bool TParseContext::integerErrorCheck(TIntermTyped* node, const char* token)
//
// Returns true if the was an error.
//
-bool TParseContext::globalErrorCheck(const TSourceLoc& line, bool global, const char* token)
+bool TParseContext::globalErrorCheck(const TSourceLoc &line, bool global, const char *token)
{
if (global)
return false;
@@ -428,30 +445,40 @@ bool TParseContext::globalErrorCheck(const TSourceLoc& line, bool global, const
//
// Returns true if there was an error.
//
-bool TParseContext::reservedErrorCheck(const TSourceLoc& line, const TString& identifier)
+bool TParseContext::reservedErrorCheck(const TSourceLoc &line, const TString &identifier)
{
- static const char* reservedErrMsg = "reserved built-in name";
- if (!symbolTable.atBuiltInLevel()) {
- if (identifier.compare(0, 3, "gl_") == 0) {
+ static const char *reservedErrMsg = "reserved built-in name";
+ if (!symbolTable.atBuiltInLevel())
+ {
+ if (identifier.compare(0, 3, "gl_") == 0)
+ {
error(line, reservedErrMsg, "gl_");
return true;
}
- if (IsWebGLBasedSpec(shaderSpec)) {
- if (identifier.compare(0, 6, "webgl_") == 0) {
+ if (IsWebGLBasedSpec(mShaderSpec))
+ {
+ if (identifier.compare(0, 6, "webgl_") == 0)
+ {
error(line, reservedErrMsg, "webgl_");
return true;
}
- if (identifier.compare(0, 7, "_webgl_") == 0) {
+ if (identifier.compare(0, 7, "_webgl_") == 0)
+ {
error(line, reservedErrMsg, "_webgl_");
return true;
}
- if (shaderSpec == SH_CSS_SHADERS_SPEC && identifier.compare(0, 4, "css_") == 0) {
+ if (mShaderSpec == SH_CSS_SHADERS_SPEC && identifier.compare(0, 4, "css_") == 0)
+ {
error(line, reservedErrMsg, "css_");
return true;
}
}
- if (identifier.find("__") != TString::npos) {
- error(line, "identifiers containing two consecutive underscores (__) are reserved as possible future keywords", identifier.c_str());
+ if (identifier.find("__") != TString::npos)
+ {
+ error(line,
+ "identifiers containing two consecutive underscores (__) are reserved as "
+ "possible future keywords",
+ identifier.c_str());
return true;
}
}
@@ -466,19 +493,30 @@ bool TParseContext::reservedErrorCheck(const TSourceLoc& line, const TString& id
//
// Returns true if there was an error in construction.
//
-bool TParseContext::constructorErrorCheck(const TSourceLoc& line, TIntermNode* node, TFunction& function, TOperator op, TType* type)
+bool TParseContext::constructorErrorCheck(const TSourceLoc &line,
+ TIntermNode *argumentsNode,
+ TFunction &function,
+ TOperator op,
+ TType *type)
{
*type = function.getReturnType();
bool constructingMatrix = false;
- switch(op) {
- case EOpConstructMat2:
- case EOpConstructMat3:
- case EOpConstructMat4:
- constructingMatrix = true;
- break;
- default:
- break;
+ switch (op)
+ {
+ case EOpConstructMat2:
+ case EOpConstructMat2x3:
+ case EOpConstructMat2x4:
+ case EOpConstructMat3x2:
+ case EOpConstructMat3:
+ case EOpConstructMat3x4:
+ case EOpConstructMat4x2:
+ case EOpConstructMat4x3:
+ case EOpConstructMat4:
+ constructingMatrix = true;
+ break;
+ default:
+ break;
}
//
@@ -487,16 +525,17 @@ bool TParseContext::constructorErrorCheck(const TSourceLoc& line, TIntermNode* n
// again, there is an extra argument, so 'overfull' will become true.
//
- size_t size = 0;
- bool constType = true;
- bool full = false;
- bool overFull = false;
+ size_t size = 0;
+ bool constType = true;
+ bool full = false;
+ bool overFull = false;
bool matrixInMatrix = false;
bool arrayArg = false;
- for (size_t i = 0; i < function.getParamCount(); ++i) {
- const TParameter& param = function.getParam(i);
+ for (size_t i = 0; i < function.getParamCount(); ++i)
+ {
+ const TConstParameter &param = function.getParam(i);
size += param.type->getObjectSize();
-
+
if (constructingMatrix && param.type->isMatrix())
matrixInMatrix = true;
if (full)
@@ -508,162 +547,184 @@ bool TParseContext::constructorErrorCheck(const TSourceLoc& line, TIntermNode* n
if (param.type->isArray())
arrayArg = true;
}
-
+
if (constType)
type->setQualifier(EvqConst);
- if (type->isArray() && static_cast<size_t>(type->getArraySize()) != function.getParamCount()) {
- error(line, "array constructor needs one argument per array element", "constructor");
- return true;
+ if (type->isArray())
+ {
+ if (type->isUnsizedArray())
+ {
+ type->setArraySize(static_cast<int>(function.getParamCount()));
+ }
+ else if (static_cast<size_t>(type->getArraySize()) != function.getParamCount())
+ {
+ error(line, "array constructor needs one argument per array element", "constructor");
+ return true;
+ }
}
- if (arrayArg && op != EOpConstructStruct) {
+ if (arrayArg && op != EOpConstructStruct)
+ {
error(line, "constructing from a non-dereferenced array", "constructor");
return true;
}
- if (matrixInMatrix && !type->isArray()) {
- if (function.getParamCount() != 1) {
- error(line, "constructing matrix from matrix can only take one argument", "constructor");
- return true;
+ if (matrixInMatrix && !type->isArray())
+ {
+ if (function.getParamCount() != 1)
+ {
+ error(line, "constructing matrix from matrix can only take one argument",
+ "constructor");
+ return true;
}
}
- if (overFull) {
+ if (overFull)
+ {
error(line, "too many arguments", "constructor");
return true;
}
-
- if (op == EOpConstructStruct && !type->isArray() && type->getStruct()->fields().size() != function.getParamCount()) {
- error(line, "Number of constructor parameters does not match the number of structure fields", "constructor");
+
+ if (op == EOpConstructStruct && !type->isArray() &&
+ type->getStruct()->fields().size() != function.getParamCount())
+ {
+ error(line,
+ "Number of constructor parameters does not match the number of structure fields",
+ "constructor");
return true;
}
- if (!type->isMatrix() || !matrixInMatrix) {
+ if (!type->isMatrix() || !matrixInMatrix)
+ {
if ((op != EOpConstructStruct && size != 1 && size < type->getObjectSize()) ||
- (op == EOpConstructStruct && size < type->getObjectSize())) {
+ (op == EOpConstructStruct && size < type->getObjectSize()))
+ {
error(line, "not enough data provided for construction", "constructor");
return true;
}
}
- TIntermTyped *typed = node ? node->getAsTyped() : 0;
- if (typed == 0) {
- error(line, "constructor argument does not have a type", "constructor");
- return true;
- }
- if (op != EOpConstructStruct && IsSampler(typed->getBasicType())) {
- error(line, "cannot convert a sampler", "constructor");
+ if (argumentsNode == nullptr)
+ {
+ error(line, "constructor does not have any arguments", "constructor");
return true;
}
- if (typed->getBasicType() == EbtVoid) {
- error(line, "cannot convert a void", "constructor");
- return true;
+
+ TIntermAggregate *argumentsAgg = argumentsNode->getAsAggregate();
+ for (TIntermNode *&argNode : *argumentsAgg->getSequence())
+ {
+ TIntermTyped *argTyped = argNode->getAsTyped();
+ ASSERT(argTyped != nullptr);
+ if (op != EOpConstructStruct && IsSampler(argTyped->getBasicType()))
+ {
+ error(line, "cannot convert a sampler", "constructor");
+ return true;
+ }
+ if (argTyped->getBasicType() == EbtVoid)
+ {
+ error(line, "cannot convert a void", "constructor");
+ return true;
+ }
}
return false;
}
-// This function checks to see if a void variable has been declared and raise an error message for such a case
+// This function checks to see if a void variable has been declared and raise an error message for
+// such a case
//
// returns true in case of an error
//
-bool TParseContext::voidErrorCheck(const TSourceLoc& line, const TString& identifier, const TPublicType& pubType)
+bool TParseContext::voidErrorCheck(const TSourceLoc &line,
+ const TString &identifier,
+ const TBasicType &type)
{
- if (pubType.type == EbtVoid) {
+ if (type == EbtVoid)
+ {
error(line, "illegal use of type 'void'", identifier.c_str());
return true;
- }
+ }
return false;
}
-// This function checks to see if the node (for the expression) contains a scalar boolean expression or not
+// This function checks to see if the node (for the expression) contains a scalar boolean expression
+// or not
//
// returns true in case of an error
//
-bool TParseContext::boolErrorCheck(const TSourceLoc& line, const TIntermTyped* type)
+bool TParseContext::boolErrorCheck(const TSourceLoc &line, const TIntermTyped *type)
{
- if (type->getBasicType() != EbtBool || type->isArray() || type->isMatrix() || type->isVector()) {
+ if (type->getBasicType() != EbtBool || type->isArray() || type->isMatrix() || type->isVector())
+ {
error(line, "boolean expression expected", "");
return true;
- }
+ }
return false;
}
-// This function checks to see if the node (for the expression) contains a scalar boolean expression or not
+// This function checks to see if the node (for the expression) contains a scalar boolean expression
+// or not
//
// returns true in case of an error
//
-bool TParseContext::boolErrorCheck(const TSourceLoc& line, const TPublicType& pType)
+bool TParseContext::boolErrorCheck(const TSourceLoc &line, const TPublicType &pType)
{
- if (pType.type != EbtBool || pType.isAggregate()) {
+ if (pType.type != EbtBool || pType.isAggregate())
+ {
error(line, "boolean expression expected", "");
return true;
- }
-
- return false;
-}
-
-bool TParseContext::samplerErrorCheck(const TSourceLoc& line, const TPublicType& pType, const char* reason)
-{
- if (pType.type == EbtStruct) {
- if (containsSampler(*pType.userDef)) {
- error(line, reason, getBasicString(pType.type), "(structure contains a sampler)");
-
- return true;
- }
-
- return false;
- } else if (IsSampler(pType.type)) {
- error(line, reason, getBasicString(pType.type));
-
- return true;
}
return false;
}
-bool TParseContext::structQualifierErrorCheck(const TSourceLoc& line, const TPublicType& pType)
+bool TParseContext::samplerErrorCheck(const TSourceLoc &line,
+ const TPublicType &pType,
+ const char *reason)
{
- switch (pType.qualifier)
+ if (pType.type == EbtStruct)
{
- case EvqVaryingIn:
- case EvqVaryingOut:
- case EvqAttribute:
- case EvqVertexIn:
- case EvqFragmentOut:
- if (pType.type == EbtStruct)
+ if (containsSampler(*pType.userDef))
{
- error(line, "cannot be used with a structure", getQualifierString(pType.qualifier));
+ error(line, reason, getBasicString(pType.type), "(structure contains a sampler)");
+
return true;
}
- default: break;
+ return false;
}
+ else if (IsSampler(pType.type))
+ {
+ error(line, reason, getBasicString(pType.type));
- if (pType.qualifier != EvqUniform && samplerErrorCheck(line, pType, "samplers must be uniform"))
return true;
+ }
return false;
}
-bool TParseContext::locationDeclaratorListCheck(const TSourceLoc& line, const TPublicType &pType)
+bool TParseContext::locationDeclaratorListCheck(const TSourceLoc &line, const TPublicType &pType)
{
if (pType.layoutQualifier.location != -1)
{
- error(line, "location must only be specified for a single input or output variable", "location");
+ error(line, "location must only be specified for a single input or output variable",
+ "location");
return true;
}
return false;
}
-bool TParseContext::parameterSamplerErrorCheck(const TSourceLoc& line, TQualifier qualifier, const TType& type)
+bool TParseContext::parameterSamplerErrorCheck(const TSourceLoc &line,
+ TQualifier qualifier,
+ const TType &type)
{
- if ((qualifier == EvqOut || qualifier == EvqInOut) &&
- type.getBasicType() != EbtStruct && IsSampler(type.getBasicType())) {
+ if ((qualifier == EvqOut || qualifier == EvqInOut) && type.getBasicType() != EbtStruct &&
+ IsSampler(type.getBasicType()))
+ {
error(line, "samplers cannot be output parameters", type.getBasicString());
return true;
}
@@ -671,14 +732,16 @@ bool TParseContext::parameterSamplerErrorCheck(const TSourceLoc& line, TQualifie
return false;
}
-bool TParseContext::containsSampler(TType& type)
+bool TParseContext::containsSampler(const TType &type)
{
if (IsSampler(type.getBasicType()))
return true;
- if (type.getBasicType() == EbtStruct || type.isInterfaceBlock()) {
- const TFieldList& fields = type.getStruct()->fields();
- for (unsigned int i = 0; i < fields.size(); ++i) {
+ if (type.getBasicType() == EbtStruct || type.isInterfaceBlock())
+ {
+ const TFieldList &fields = type.getStruct()->fields();
+ for (unsigned int i = 0; i < fields.size(); ++i)
+ {
if (containsSampler(*fields[i]->type()))
return true;
}
@@ -692,13 +755,17 @@ bool TParseContext::containsSampler(TType& type)
//
// Returns true if there was an error.
//
-bool TParseContext::arraySizeErrorCheck(const TSourceLoc& line, TIntermTyped* expr, int& size)
+bool TParseContext::arraySizeErrorCheck(const TSourceLoc &line, TIntermTyped *expr, int &size)
{
- TIntermConstantUnion* constant = expr->getAsConstantUnion();
+ TIntermConstantUnion *constant = expr->getAsConstantUnion();
- if (constant == 0 || !constant->isScalarInt())
+ // TODO(oetuaho@nvidia.com): Get rid of the constant == nullptr check here once all constant
+ // expressions can be folded. Right now we don't allow constant expressions that ANGLE can't
+ // fold as array size.
+ if (expr->getQualifier() != EvqConst || constant == nullptr || !constant->isScalarInt())
{
error(line, "array size must be a constant integer expression", "");
+ size = 1;
return true;
}
@@ -707,7 +774,7 @@ bool TParseContext::arraySizeErrorCheck(const TSourceLoc& line, TIntermTyped* ex
if (constant->getBasicType() == EbtUInt)
{
unsignedSize = constant->getUConst(0);
- size = static_cast<int>(unsignedSize);
+ size = static_cast<int>(unsignedSize);
}
else
{
@@ -750,10 +817,13 @@ bool TParseContext::arraySizeErrorCheck(const TSourceLoc& line, TIntermTyped* ex
//
// Returns true if there is an error.
//
-bool TParseContext::arrayQualifierErrorCheck(const TSourceLoc& line, TPublicType type)
+bool TParseContext::arrayQualifierErrorCheck(const TSourceLoc &line, const TPublicType &type)
{
- if ((type.qualifier == EvqAttribute) || (type.qualifier == EvqVertexIn) || (type.qualifier == EvqConst)) {
- error(line, "cannot declare arrays of this qualifier", TType(type).getCompleteString().c_str());
+ if ((type.qualifier == EvqAttribute) || (type.qualifier == EvqVertexIn) ||
+ (type.qualifier == EvqConst && mShaderVersion < 300))
+ {
+ error(line, "cannot declare arrays of this qualifier",
+ TType(type).getCompleteString().c_str());
return true;
}
@@ -765,93 +835,25 @@ bool TParseContext::arrayQualifierErrorCheck(const TSourceLoc& line, TPublicType
//
// Returns true if there is an error.
//
-bool TParseContext::arrayTypeErrorCheck(const TSourceLoc& line, TPublicType type)
+bool TParseContext::arrayTypeErrorCheck(const TSourceLoc &line, const TPublicType &type)
{
//
// Can the type be an array?
//
- if (type.array) {
+ if (type.array)
+ {
error(line, "cannot declare arrays of arrays", TType(type).getCompleteString().c_str());
return true;
}
-
- return false;
-}
-
-//
-// Do all the semantic checking for declaring an array, with and
-// without a size, and make the right changes to the symbol table.
-//
-// size == 0 means no specified size.
-//
-// Returns true if there was an error.
-//
-bool TParseContext::arrayErrorCheck(const TSourceLoc& line, const TString& identifier, const TPublicType &type, TVariable*& variable)
-{
- //
- // Don't check for reserved word use until after we know it's not in the symbol table,
- // because reserved arrays can be redeclared.
- //
-
- bool builtIn = false;
- bool sameScope = false;
- TSymbol* symbol = symbolTable.find(identifier, 0, &builtIn, &sameScope);
- if (symbol == 0 || !sameScope) {
- bool needsReservedErrorCheck = true;
-
- // gl_LastFragData may be redeclared with a new precision qualifier
- if (identifier.compare(0, 15, "gl_LastFragData") == 0) {
- if (type.arraySize == static_cast<const TVariable*>(symbolTable.findBuiltIn("gl_MaxDrawBuffers", shaderVersion))->getConstPointer()->getIConst()) {
- if (TSymbol* builtInSymbol = symbolTable.findBuiltIn(identifier, shaderVersion)) {
- needsReservedErrorCheck = extensionErrorCheck(line, builtInSymbol->getExtension());
- }
- } else {
- error(line, "redeclaration of array with size != gl_MaxDrawBuffers", identifier.c_str());
- return true;
- }
- }
-
- if (needsReservedErrorCheck)
- if (reservedErrorCheck(line, identifier))
- return true;
-
- variable = new TVariable(&identifier, TType(type));
-
- if (type.arraySize)
- variable->getType().setArraySize(type.arraySize);
-
- if (! symbolTable.declare(variable)) {
- delete variable;
- error(line, "INTERNAL ERROR inserting new symbol", identifier.c_str());
- return true;
- }
- } else {
- if (! symbol->isVariable()) {
- error(line, "variable expected", identifier.c_str());
- return true;
- }
-
- variable = static_cast<TVariable*>(symbol);
- if (! variable->getType().isArray()) {
- error(line, "redeclaring non-array as array", identifier.c_str());
- return true;
- }
- if (variable->getType().getArraySize() > 0) {
- error(line, "redeclaration of array with size", identifier.c_str());
- return true;
- }
-
- if (! variable->getType().sameElementType(TType(type))) {
- error(line, "redeclaration of array with a different type", identifier.c_str());
- return true;
- }
-
- if (type.arraySize)
- variable->getType().setArraySize(type.arraySize);
- }
-
- if (voidErrorCheck(line, identifier, type))
+ // In ESSL1.00 shaders, structs cannot be varying (section 4.3.5). This is checked elsewhere.
+ // In ESSL3.00 shaders, struct inputs/outputs are allowed but not arrays of structs (section
+ // 4.3.4).
+ if (mShaderVersion >= 300 && type.type == EbtStruct && sh::IsVarying(type.qualifier))
+ {
+ error(line, "cannot declare arrays of structs of this qualifier",
+ TType(type).getCompleteString().c_str());
return true;
+ }
return false;
}
@@ -861,20 +863,24 @@ bool TParseContext::arrayErrorCheck(const TSourceLoc& line, const TString& ident
//
// Returns true if there was an error.
//
-bool TParseContext::nonInitConstErrorCheck(const TSourceLoc& line, const TString& identifier, TPublicType& type, bool array)
+bool TParseContext::nonInitErrorCheck(const TSourceLoc &line,
+ const TString &identifier,
+ TPublicType *type)
{
- if (type.qualifier == EvqConst)
+ ASSERT(type != nullptr);
+ if (type->qualifier == EvqConst)
{
// Make the qualifier make sense.
- type.qualifier = EvqTemporary;
-
- if (array)
- {
- error(line, "arrays may not be declared constant since they cannot be initialized", identifier.c_str());
- }
- else if (type.isStructureContainingArrays())
+ type->qualifier = EvqTemporary;
+
+ // Generate informative error messages for ESSL1.
+ // In ESSL3 arrays and structures containing arrays can be constant.
+ if (mShaderVersion < 300 && type->isStructureContainingArrays())
{
- error(line, "structures containing arrays may not be declared constant since they cannot be initialized", identifier.c_str());
+ error(line,
+ "structures containing arrays may not be declared constant since they cannot be "
+ "initialized",
+ identifier.c_str());
}
else
{
@@ -883,44 +889,79 @@ bool TParseContext::nonInitConstErrorCheck(const TSourceLoc& line, const TString
return true;
}
-
+ if (type->isUnsizedArray())
+ {
+ error(line, "implicitly sized arrays need to be initialized", identifier.c_str());
+ return true;
+ }
return false;
}
-//
-// Do semantic checking for a variable declaration that has no initializer,
+// Do some simple checks that are shared between all variable declarations,
// and update the symbol table.
//
-// Returns true if there was an error.
+// Returns true if declaring the variable succeeded.
//
-bool TParseContext::nonInitErrorCheck(const TSourceLoc& line, const TString& identifier, const TPublicType& type, TVariable*& variable)
+bool TParseContext::declareVariable(const TSourceLoc &line,
+ const TString &identifier,
+ const TType &type,
+ TVariable **variable)
{
- if (reservedErrorCheck(line, identifier))
- recover();
+ ASSERT((*variable) == nullptr);
- variable = new TVariable(&identifier, TType(type));
+ bool needsReservedErrorCheck = true;
- if (! symbolTable.declare(variable)) {
- error(line, "redefinition", variable->getName().c_str());
- delete variable;
- variable = 0;
- return true;
+ // gl_LastFragData may be redeclared with a new precision qualifier
+ if (type.isArray() && identifier.compare(0, 15, "gl_LastFragData") == 0)
+ {
+ const TVariable *maxDrawBuffers = static_cast<const TVariable *>(
+ symbolTable.findBuiltIn("gl_MaxDrawBuffers", mShaderVersion));
+ if (type.getArraySize() == maxDrawBuffers->getConstPointer()->getIConst())
+ {
+ if (TSymbol *builtInSymbol = symbolTable.findBuiltIn(identifier, mShaderVersion))
+ {
+ needsReservedErrorCheck = extensionErrorCheck(line, builtInSymbol->getExtension());
+ }
+ }
+ else
+ {
+ error(line, "redeclaration of gl_LastFragData with size != gl_MaxDrawBuffers",
+ identifier.c_str());
+ return false;
+ }
}
- if (voidErrorCheck(line, identifier, type))
- return true;
+ if (needsReservedErrorCheck && reservedErrorCheck(line, identifier))
+ return false;
- return false;
+ (*variable) = new TVariable(&identifier, type);
+ if (!symbolTable.declare(*variable))
+ {
+ error(line, "redefinition", identifier.c_str());
+ *variable = nullptr;
+ return false;
+ }
+
+ if (voidErrorCheck(line, identifier, type.getBasicType()))
+ return false;
+
+ return true;
}
-bool TParseContext::paramErrorCheck(const TSourceLoc& line, TQualifier qualifier, TQualifier paramQualifier, TType* type)
-{
- if (qualifier != EvqConst && qualifier != EvqTemporary) {
+bool TParseContext::paramErrorCheck(const TSourceLoc &line,
+ TQualifier qualifier,
+ TQualifier paramQualifier,
+ TType *type)
+{
+ if (qualifier != EvqConst && qualifier != EvqTemporary)
+ {
error(line, "qualifier not allowed on function parameter", getQualifierString(qualifier));
return true;
}
- if (qualifier == EvqConst && paramQualifier != EvqIn) {
- error(line, "qualifier not allowed with ", getQualifierString(qualifier), getQualifierString(paramQualifier));
+ if (qualifier == EvqConst && paramQualifier != EvqIn)
+ {
+ error(line, "qualifier not allowed with ", getQualifierString(qualifier),
+ getQualifierString(paramQualifier));
return true;
}
@@ -932,20 +973,23 @@ bool TParseContext::paramErrorCheck(const TSourceLoc& line, TQualifier qualifier
return false;
}
-bool TParseContext::extensionErrorCheck(const TSourceLoc& line, const TString& extension)
+bool TParseContext::extensionErrorCheck(const TSourceLoc &line, const TString &extension)
{
- const TExtensionBehavior& extBehavior = extensionBehavior();
+ const TExtensionBehavior &extBehavior = extensionBehavior();
TExtensionBehavior::const_iterator iter = extBehavior.find(extension.c_str());
- if (iter == extBehavior.end()) {
+ if (iter == extBehavior.end())
+ {
error(line, "extension", extension.c_str(), "is not supported");
return true;
}
// In GLSL ES, an extension's default behavior is "disable".
- if (iter->second == EBhDisable || iter->second == EBhUndefined) {
+ if (iter->second == EBhDisable || iter->second == EBhUndefined)
+ {
error(line, "extension", extension.c_str(), "is disabled");
return true;
}
- if (iter->second == EBhWarn) {
+ if (iter->second == EBhWarn)
+ {
warning(line, "extension", extension.c_str(), "is being used");
return false;
}
@@ -953,27 +997,57 @@ bool TParseContext::extensionErrorCheck(const TSourceLoc& line, const TString& e
return false;
}
-bool TParseContext::singleDeclarationErrorCheck(TPublicType &publicType, const TSourceLoc& identifierLocation, const TString &identifier)
+// These checks are common for all declarations starting a declarator list, and declarators that
+// follow an empty declaration.
+//
+bool TParseContext::singleDeclarationErrorCheck(const TPublicType &publicType,
+ const TSourceLoc &identifierLocation)
{
- if (structQualifierErrorCheck(identifierLocation, publicType))
+ switch (publicType.qualifier)
+ {
+ case EvqVaryingIn:
+ case EvqVaryingOut:
+ case EvqAttribute:
+ case EvqVertexIn:
+ case EvqFragmentOut:
+ if (publicType.type == EbtStruct)
+ {
+ error(identifierLocation, "cannot be used with a structure",
+ getQualifierString(publicType.qualifier));
+ return true;
+ }
+
+ default:
+ break;
+ }
+
+ if (publicType.qualifier != EvqUniform &&
+ samplerErrorCheck(identifierLocation, publicType, "samplers must be uniform"))
+ {
return true;
+ }
// check for layout qualifier issues
const TLayoutQualifier layoutQualifier = publicType.layoutQualifier;
if (layoutQualifier.matrixPacking != EmpUnspecified)
{
- error(identifierLocation, "layout qualifier", getMatrixPackingString(layoutQualifier.matrixPacking), "only valid for interface blocks");
+ error(identifierLocation, "layout qualifier",
+ getMatrixPackingString(layoutQualifier.matrixPacking),
+ "only valid for interface blocks");
return true;
}
if (layoutQualifier.blockStorage != EbsUnspecified)
{
- error(identifierLocation, "layout qualifier", getBlockStorageString(layoutQualifier.blockStorage), "only valid for interface blocks");
+ error(identifierLocation, "layout qualifier",
+ getBlockStorageString(layoutQualifier.blockStorage),
+ "only valid for interface blocks");
return true;
}
- if (publicType.qualifier != EvqVertexIn && publicType.qualifier != EvqFragmentOut && layoutLocationErrorCheck(identifierLocation, publicType.layoutQualifier))
+ if (publicType.qualifier != EvqVertexIn && publicType.qualifier != EvqFragmentOut &&
+ layoutLocationErrorCheck(identifierLocation, publicType.layoutQualifier))
{
return true;
}
@@ -981,18 +1055,21 @@ bool TParseContext::singleDeclarationErrorCheck(TPublicType &publicType, const T
return false;
}
-bool TParseContext::layoutLocationErrorCheck(const TSourceLoc& location, const TLayoutQualifier &layoutQualifier)
+bool TParseContext::layoutLocationErrorCheck(const TSourceLoc &location,
+ const TLayoutQualifier &layoutQualifier)
{
if (layoutQualifier.location != -1)
{
- error(location, "invalid layout qualifier:", "location", "only valid on program inputs and outputs");
+ error(location, "invalid layout qualifier:", "location",
+ "only valid on program inputs and outputs");
return true;
}
return false;
}
-bool TParseContext::functionCallLValueErrorCheck(const TFunction *fnCandidate, TIntermAggregate *aggregate)
+bool TParseContext::functionCallLValueErrorCheck(const TFunction *fnCandidate,
+ TIntermAggregate *aggregate)
{
for (size_t i = 0; i < fnCandidate->getParamCount(); ++i)
{
@@ -1003,7 +1080,7 @@ bool TParseContext::functionCallLValueErrorCheck(const TFunction *fnCandidate, T
if (lValueErrorCheck(node->getLine(), "assign", node))
{
error(node->getLine(),
- "Constant value cannot be passed for 'out' or 'inout' parameters.", "Error");
+ "Constant value cannot be passed for 'out' or 'inout' parameters.", "Error");
recover();
return true;
}
@@ -1012,40 +1089,47 @@ bool TParseContext::functionCallLValueErrorCheck(const TFunction *fnCandidate, T
return false;
}
-bool TParseContext::supportsExtension(const char* extension)
+void TParseContext::es3InvariantErrorCheck(const TQualifier qualifier,
+ const TSourceLoc &invariantLocation)
{
- const TExtensionBehavior& extbehavior = extensionBehavior();
- TExtensionBehavior::const_iterator iter = extbehavior.find(extension);
- return (iter != extbehavior.end());
+ if (!sh::IsVaryingOut(qualifier) && qualifier != EvqFragmentOut)
+ {
+ error(invariantLocation, "Only out variables can be invariant.", "invariant");
+ recover();
+ }
}
-bool TParseContext::isExtensionEnabled(const char* extension) const
+bool TParseContext::supportsExtension(const char *extension)
{
- const TExtensionBehavior& extbehavior = extensionBehavior();
+ const TExtensionBehavior &extbehavior = extensionBehavior();
TExtensionBehavior::const_iterator iter = extbehavior.find(extension);
+ return (iter != extbehavior.end());
+}
- if (iter == extbehavior.end())
- {
- return false;
- }
-
- return (iter->second == EBhEnable || iter->second == EBhRequire);
+bool TParseContext::isExtensionEnabled(const char *extension) const
+{
+ return ::IsExtensionEnabled(extensionBehavior(), extension);
}
-void TParseContext::handleExtensionDirective(const TSourceLoc& loc, const char* extName, const char* behavior)
+void TParseContext::handleExtensionDirective(const TSourceLoc &loc,
+ const char *extName,
+ const char *behavior)
{
pp::SourceLocation srcLoc;
srcLoc.file = loc.first_file;
srcLoc.line = loc.first_line;
- directiveHandler.handleExtension(srcLoc, extName, behavior);
+ mDirectiveHandler.handleExtension(srcLoc, extName, behavior);
}
-void TParseContext::handlePragmaDirective(const TSourceLoc& loc, const char* name, const char* value, bool stdgl)
+void TParseContext::handlePragmaDirective(const TSourceLoc &loc,
+ const char *name,
+ const char *value,
+ bool stdgl)
{
pp::SourceLocation srcLoc;
srcLoc.file = loc.first_file;
srcLoc.line = loc.first_line;
- directiveHandler.handlePragma(srcLoc, name, value, stdgl);
+ mDirectiveHandler.handlePragma(srcLoc, name, value, stdgl);
}
/////////////////////////////////////////////////////////////////////////////////
@@ -1072,14 +1156,46 @@ const TVariable *TParseContext::getNamedVariable(const TSourceLoc &location,
}
else
{
- variable = static_cast<const TVariable*>(symbol);
+ variable = static_cast<const TVariable *>(symbol);
- if (symbolTable.findBuiltIn(variable->getName(), shaderVersion) &&
+ if (symbolTable.findBuiltIn(variable->getName(), mShaderVersion) &&
!variable->getExtension().empty() &&
extensionErrorCheck(location, variable->getExtension()))
{
recover();
}
+
+ // Reject shaders using both gl_FragData and gl_FragColor
+ TQualifier qualifier = variable->getType().getQualifier();
+ if (qualifier == EvqFragData || qualifier == EvqSecondaryFragDataEXT)
+ {
+ mUsesFragData = true;
+ }
+ else if (qualifier == EvqFragColor || qualifier == EvqSecondaryFragColorEXT)
+ {
+ mUsesFragColor = true;
+ }
+ if (qualifier == EvqSecondaryFragDataEXT || qualifier == EvqSecondaryFragColorEXT)
+ {
+ mUsesSecondaryOutputs = true;
+ }
+
+ // This validation is not quite correct - it's only an error to write to
+ // both FragData and FragColor. For simplicity, and because users shouldn't
+ // be rewarded for reading from undefined varaibles, return an error
+ // if they are both referenced, rather than assigned.
+ if (mUsesFragData && mUsesFragColor)
+ {
+ const char *errorMessage = "cannot use both gl_FragData and gl_FragColor";
+ if (mUsesSecondaryOutputs)
+ {
+ errorMessage =
+ "cannot use both output variable sets (gl_FragData, gl_SecondaryFragDataEXT)"
+ " and (gl_FragColor, gl_SecondaryFragColorEXT)";
+ }
+ error(location, errorMessage, name->c_str());
+ recover();
+ }
}
if (!variable)
@@ -1093,32 +1209,56 @@ const TVariable *TParseContext::getNamedVariable(const TSourceLoc &location,
return variable;
}
+TIntermTyped *TParseContext::parseVariableIdentifier(const TSourceLoc &location,
+ const TString *name,
+ const TSymbol *symbol)
+{
+ const TVariable *variable = getNamedVariable(location, name, symbol);
+
+ if (variable->getConstPointer())
+ {
+ const TConstantUnion *constArray = variable->getConstPointer();
+ return intermediate.addConstantUnion(constArray, variable->getType(), location);
+ }
+ else
+ {
+ return intermediate.addSymbol(variable->getUniqueId(), variable->getName(),
+ variable->getType(), location);
+ }
+}
+
//
// Look up a function name in the symbol table, and make sure it is a function.
//
// Return the function symbol if found, otherwise 0.
//
-const TFunction* TParseContext::findFunction(const TSourceLoc& line, TFunction* call, int inputShaderVersion, bool *builtIn)
+const TFunction *TParseContext::findFunction(const TSourceLoc &line,
+ TFunction *call,
+ int inputShaderVersion,
+ bool *builtIn)
{
// First find by unmangled name to check whether the function name has been
// hidden by a variable name or struct typename.
// If a function is found, check for one with a matching argument list.
- const TSymbol* symbol = symbolTable.find(call->getName(), inputShaderVersion, builtIn);
- if (symbol == 0 || symbol->isFunction()) {
+ const TSymbol *symbol = symbolTable.find(call->getName(), inputShaderVersion, builtIn);
+ if (symbol == 0 || symbol->isFunction())
+ {
symbol = symbolTable.find(call->getMangledName(), inputShaderVersion, builtIn);
}
- if (symbol == 0) {
+ if (symbol == 0)
+ {
error(line, "no matching overloaded function found", call->getName().c_str());
return 0;
}
- if (!symbol->isFunction()) {
+ if (!symbol->isFunction())
+ {
error(line, "function name expected", call->getName().c_str());
return 0;
}
- return static_cast<const TFunction*>(symbol);
+ return static_cast<const TFunction *>(symbol);
}
//
@@ -1127,44 +1267,61 @@ const TFunction* TParseContext::findFunction(const TSourceLoc& line, TFunction*
//
// Returns true on error, false if no error
//
-bool TParseContext::executeInitializer(const TSourceLoc& line, const TString& identifier, TPublicType& pType,
- TIntermTyped* initializer, TIntermNode*& intermNode, TVariable* variable)
+bool TParseContext::executeInitializer(const TSourceLoc &line,
+ const TString &identifier,
+ const TPublicType &pType,
+ TIntermTyped *initializer,
+ TIntermNode **intermNode)
{
+ ASSERT(intermNode != nullptr);
TType type = TType(pType);
- if (variable == 0) {
- if (reservedErrorCheck(line, identifier))
- return true;
-
- if (voidErrorCheck(line, identifier, pType))
- return true;
+ TVariable *variable = nullptr;
+ if (type.isUnsizedArray())
+ {
+ type.setArraySize(initializer->getArraySize());
+ }
+ if (!declareVariable(line, identifier, type, &variable))
+ {
+ return true;
+ }
- //
- // add variable to symbol table
- //
- variable = new TVariable(&identifier, type);
- if (! symbolTable.declare(variable)) {
- error(line, "redefinition", variable->getName().c_str());
- return true;
- // don't delete variable, it's used by error recovery, and the pool
- // pop will take care of the memory
- }
+ bool globalInitWarning = false;
+ if (symbolTable.atGlobalLevel() &&
+ !ValidateGlobalInitializer(initializer, this, &globalInitWarning))
+ {
+ // Error message does not completely match behavior with ESSL 1.00, but
+ // we want to steer developers towards only using constant expressions.
+ error(line, "global variable initializers must be constant expressions", "=");
+ return true;
+ }
+ if (globalInitWarning)
+ {
+ warning(
+ line,
+ "global variable initializers should be constant expressions "
+ "(uniforms and globals are allowed in global initializers for legacy compatibility)",
+ "=");
}
//
// identifier must be of type constant, a global, or a temporary
//
TQualifier qualifier = variable->getType().getQualifier();
- if ((qualifier != EvqTemporary) && (qualifier != EvqGlobal) && (qualifier != EvqConst)) {
- error(line, " cannot initialize this type of qualifier ", variable->getType().getQualifierString());
+ if ((qualifier != EvqTemporary) && (qualifier != EvqGlobal) && (qualifier != EvqConst))
+ {
+ error(line, " cannot initialize this type of qualifier ",
+ variable->getType().getQualifierString());
return true;
}
//
// test for and propagate constant
//
- if (qualifier == EvqConst) {
- if (qualifier != initializer->getType().getQualifier()) {
+ if (qualifier == EvqConst)
+ {
+ if (qualifier != initializer->getType().getQualifier())
+ {
std::stringstream extraInfoStream;
extraInfoStream << "'" << variable->getType().getCompleteString() << "'";
std::string extraInfo = extraInfoStream.str();
@@ -1172,78 +1329,74 @@ bool TParseContext::executeInitializer(const TSourceLoc& line, const TString& id
variable->getType().setQualifier(EvqTemporary);
return true;
}
- if (type != initializer->getType()) {
- error(line, " non-matching types for const initializer ",
- variable->getType().getQualifierString());
+ if (type != initializer->getType())
+ {
+ error(line, " non-matching types for const initializer ",
+ variable->getType().getQualifierString());
variable->getType().setQualifier(EvqTemporary);
return true;
}
- if (initializer->getAsConstantUnion()) {
+
+ // Save the constant folded value to the variable if possible. For example array
+ // initializers are not folded, since that way copying the array literal to multiple places
+ // in the shader is avoided.
+ // TODO(oetuaho@nvidia.com): Consider constant folding array initialization in cases where
+ // it would be beneficial.
+ if (initializer->getAsConstantUnion())
+ {
variable->shareConstPointer(initializer->getAsConstantUnion()->getUnionArrayPointer());
- } else if (initializer->getAsSymbolNode()) {
- const TSymbol* symbol = symbolTable.find(initializer->getAsSymbolNode()->getSymbol(), 0);
- const TVariable* tVar = static_cast<const TVariable*>(symbol);
+ *intermNode = nullptr;
+ return false;
+ }
+ else if (initializer->getAsSymbolNode())
+ {
+ const TSymbol *symbol =
+ symbolTable.find(initializer->getAsSymbolNode()->getSymbol(), 0);
+ const TVariable *tVar = static_cast<const TVariable *>(symbol);
- ConstantUnion* constArray = tVar->getConstPointer();
- variable->shareConstPointer(constArray);
- } else {
- std::stringstream extraInfoStream;
- extraInfoStream << "'" << variable->getType().getCompleteString() << "'";
- std::string extraInfo = extraInfoStream.str();
- error(line, " cannot assign to", "=", extraInfo.c_str());
- variable->getType().setQualifier(EvqTemporary);
- return true;
+ const TConstantUnion *constArray = tVar->getConstPointer();
+ if (constArray)
+ {
+ variable->shareConstPointer(constArray);
+ *intermNode = nullptr;
+ return false;
+ }
}
}
-
- if (qualifier != EvqConst) {
- TIntermSymbol* intermSymbol = intermediate.addSymbol(variable->getUniqueId(), variable->getName(), variable->getType(), line);
- intermNode = createAssign(EOpInitialize, intermSymbol, initializer, line);
- if (intermNode == 0) {
- assignError(line, "=", intermSymbol->getCompleteString(), initializer->getCompleteString());
- return true;
- }
- } else
- intermNode = 0;
-
- return false;
-}
-
-bool TParseContext::areAllChildConst(TIntermAggregate* aggrNode)
-{
- ASSERT(aggrNode != NULL);
- if (!aggrNode->isConstructor())
- return false;
-
- bool allConstant = true;
- // check if all the child nodes are constants so that they can be inserted into
- // the parent node
- TIntermSequence *sequence = aggrNode->getSequence() ;
- for (TIntermSequence::iterator p = sequence->begin(); p != sequence->end(); ++p) {
- if (!(*p)->getAsTyped()->getAsConstantUnion())
- return false;
+ TIntermSymbol *intermSymbol = intermediate.addSymbol(
+ variable->getUniqueId(), variable->getName(), variable->getType(), line);
+ *intermNode = createAssign(EOpInitialize, intermSymbol, initializer, line);
+ if (*intermNode == nullptr)
+ {
+ assignError(line, "=", intermSymbol->getCompleteString(), initializer->getCompleteString());
+ return true;
}
- return allConstant;
+ return false;
}
-TPublicType TParseContext::addFullySpecifiedType(TQualifier qualifier, TLayoutQualifier layoutQualifier, const TPublicType& typeSpecifier)
+TPublicType TParseContext::addFullySpecifiedType(TQualifier qualifier,
+ bool invariant,
+ TLayoutQualifier layoutQualifier,
+ const TPublicType &typeSpecifier)
{
- TPublicType returnType = typeSpecifier;
- returnType.qualifier = qualifier;
+ TPublicType returnType = typeSpecifier;
+ returnType.qualifier = qualifier;
+ returnType.invariant = invariant;
returnType.layoutQualifier = layoutQualifier;
- if (typeSpecifier.array)
+ if (mShaderVersion < 300)
{
- error(typeSpecifier.line, "not supported", "first-class array");
- recover();
- returnType.setArray(false);
- }
+ if (typeSpecifier.array)
+ {
+ error(typeSpecifier.line, "not supported", "first-class array");
+ recover();
+ returnType.clearArrayness();
+ }
- if (shaderVersion < 300)
- {
- if (qualifier == EvqAttribute && (typeSpecifier.type == EbtBool || typeSpecifier.type == EbtInt))
+ if (qualifier == EvqAttribute &&
+ (typeSpecifier.type == EbtBool || typeSpecifier.type == EbtInt))
{
error(typeSpecifier.line, "cannot be bool or int", getQualifierString(qualifier));
recover();
@@ -1258,134 +1411,258 @@ TPublicType TParseContext::addFullySpecifiedType(TQualifier qualifier, TLayoutQu
}
else
{
- switch (qualifier)
+ if (!layoutQualifier.isEmpty())
{
- case EvqSmoothIn:
- case EvqSmoothOut:
- case EvqVertexOut:
- case EvqFragmentIn:
- case EvqCentroidOut:
- case EvqCentroidIn:
- if (typeSpecifier.type == EbtBool)
+ if (globalErrorCheck(typeSpecifier.line, symbolTable.atGlobalLevel(), "layout"))
{
- error(typeSpecifier.line, "cannot be bool", getQualifierString(qualifier));
recover();
}
- if (typeSpecifier.type == EbtInt || typeSpecifier.type == EbtUInt)
+ }
+ if (sh::IsVarying(qualifier) || qualifier == EvqVertexIn || qualifier == EvqFragmentOut)
+ {
+ es3InputOutputTypeCheck(qualifier, typeSpecifier, typeSpecifier.line);
+ }
+ }
+
+ return returnType;
+}
+
+void TParseContext::es3InputOutputTypeCheck(const TQualifier qualifier,
+ const TPublicType &type,
+ const TSourceLoc &qualifierLocation)
+{
+ // An input/output variable can never be bool or a sampler. Samplers are checked elsewhere.
+ if (type.type == EbtBool)
+ {
+ error(qualifierLocation, "cannot be bool", getQualifierString(qualifier));
+ recover();
+ }
+
+ // Specific restrictions apply for vertex shader inputs and fragment shader outputs.
+ switch (qualifier)
+ {
+ case EvqVertexIn:
+ // ESSL 3.00 section 4.3.4
+ if (type.array)
{
- error(typeSpecifier.line, "must use 'flat' interpolation here", getQualifierString(qualifier));
+ error(qualifierLocation, "cannot be array", getQualifierString(qualifier));
recover();
}
- break;
-
- case EvqVertexIn:
- case EvqFragmentOut:
- case EvqFlatIn:
- case EvqFlatOut:
- if (typeSpecifier.type == EbtBool)
+ // Vertex inputs with a struct type are disallowed in singleDeclarationErrorCheck
+ return;
+ case EvqFragmentOut:
+ // ESSL 3.00 section 4.3.6
+ if (type.isMatrix())
{
- error(typeSpecifier.line, "cannot be bool", getQualifierString(qualifier));
+ error(qualifierLocation, "cannot be matrix", getQualifierString(qualifier));
recover();
}
+ // Fragment outputs with a struct type are disallowed in singleDeclarationErrorCheck
+ return;
+ default:
break;
+ }
- default: break;
- }
+ // Vertex shader outputs / fragment shader inputs have a different, slightly more lenient set of
+ // restrictions.
+ bool typeContainsIntegers =
+ (type.type == EbtInt || type.type == EbtUInt || type.isStructureContainingType(EbtInt) ||
+ type.isStructureContainingType(EbtUInt));
+ if (typeContainsIntegers && qualifier != EvqFlatIn && qualifier != EvqFlatOut)
+ {
+ error(qualifierLocation, "must use 'flat' interpolation here",
+ getQualifierString(qualifier));
+ recover();
}
- return returnType;
+ if (type.type == EbtStruct)
+ {
+ // ESSL 3.00 sections 4.3.4 and 4.3.6.
+ // These restrictions are only implied by the ESSL 3.00 spec, but
+ // the ESSL 3.10 spec lists these restrictions explicitly.
+ if (type.array)
+ {
+ error(qualifierLocation, "cannot be an array of structures",
+ getQualifierString(qualifier));
+ recover();
+ }
+ if (type.isStructureContainingArrays())
+ {
+ error(qualifierLocation, "cannot be a structure containing an array",
+ getQualifierString(qualifier));
+ recover();
+ }
+ if (type.isStructureContainingType(EbtStruct))
+ {
+ error(qualifierLocation, "cannot be a structure containing a structure",
+ getQualifierString(qualifier));
+ recover();
+ }
+ if (type.isStructureContainingType(EbtBool))
+ {
+ error(qualifierLocation, "cannot be a structure containing a bool",
+ getQualifierString(qualifier));
+ recover();
+ }
+ }
}
-TIntermAggregate* TParseContext::parseSingleDeclaration(TPublicType &publicType, const TSourceLoc& identifierLocation, const TString &identifier)
+TIntermAggregate *TParseContext::parseSingleDeclaration(TPublicType &publicType,
+ const TSourceLoc &identifierOrTypeLocation,
+ const TString &identifier)
{
- TIntermSymbol* symbol = intermediate.addSymbol(0, identifier, TType(publicType), identifierLocation);
- TIntermAggregate* aggregate = intermediate.makeAggregate(symbol, identifierLocation);
+ TIntermSymbol *symbol =
+ intermediate.addSymbol(0, identifier, TType(publicType), identifierOrTypeLocation);
+
+ bool emptyDeclaration = (identifier == "");
+
+ mDeferredSingleDeclarationErrorCheck = emptyDeclaration;
- if (identifier != "")
+ if (emptyDeclaration)
{
- if (singleDeclarationErrorCheck(publicType, identifierLocation, identifier))
+ if (publicType.isUnsizedArray())
+ {
+ // ESSL3 spec section 4.1.9: Array declaration which leaves the size unspecified is an
+ // error. It is assumed that this applies to empty declarations as well.
+ error(identifierOrTypeLocation, "empty array declaration needs to specify a size",
+ identifier.c_str());
+ }
+ }
+ else
+ {
+ if (singleDeclarationErrorCheck(publicType, identifierOrTypeLocation))
recover();
- // this error check can mutate the type
- if (nonInitConstErrorCheck(identifierLocation, identifier, publicType, false))
+ if (nonInitErrorCheck(identifierOrTypeLocation, identifier, &publicType))
recover();
- TVariable* variable = 0;
-
- if (nonInitErrorCheck(identifierLocation, identifier, publicType, variable))
+ TVariable *variable = nullptr;
+ if (!declareVariable(identifierOrTypeLocation, identifier, TType(publicType), &variable))
recover();
if (variable && symbol)
- {
symbol->setId(variable->getUniqueId());
- }
}
- return aggregate;
+ return intermediate.makeAggregate(symbol, identifierOrTypeLocation);
}
-TIntermAggregate* TParseContext::parseSingleArrayDeclaration(TPublicType &publicType, const TSourceLoc& identifierLocation, const TString &identifier, const TSourceLoc& indexLocation, TIntermTyped *indexExpression)
+TIntermAggregate *TParseContext::parseSingleArrayDeclaration(TPublicType &publicType,
+ const TSourceLoc &identifierLocation,
+ const TString &identifier,
+ const TSourceLoc &indexLocation,
+ TIntermTyped *indexExpression)
{
- if (singleDeclarationErrorCheck(publicType, identifierLocation, identifier))
+ mDeferredSingleDeclarationErrorCheck = false;
+
+ if (singleDeclarationErrorCheck(publicType, identifierLocation))
recover();
- // this error check can mutate the type
- if (nonInitConstErrorCheck(identifierLocation, identifier, publicType, true))
+ if (nonInitErrorCheck(identifierLocation, identifier, &publicType))
recover();
- if (arrayTypeErrorCheck(indexLocation, publicType) || arrayQualifierErrorCheck(indexLocation, publicType))
+ if (arrayTypeErrorCheck(indexLocation, publicType) ||
+ arrayQualifierErrorCheck(indexLocation, publicType))
{
recover();
}
- TPublicType arrayType = publicType;
+ TType arrayType(publicType);
int size;
if (arraySizeErrorCheck(identifierLocation, indexExpression, size))
{
recover();
}
- else
- {
- arrayType.setArray(true, size);
- }
+ // Make the type an array even if size check failed.
+ // This ensures useless error messages regarding the variable's non-arrayness won't follow.
+ arrayType.setArraySize(size);
- TIntermSymbol* symbol = intermediate.addSymbol(0, identifier, TType(arrayType), identifierLocation);
- TIntermAggregate* aggregate = intermediate.makeAggregate(symbol, identifierLocation);
- TVariable* variable = 0;
-
- if (arrayErrorCheck(identifierLocation, identifier, arrayType, variable))
+ TVariable *variable = nullptr;
+ if (!declareVariable(identifierLocation, identifier, arrayType, &variable))
recover();
+ TIntermSymbol *symbol = intermediate.addSymbol(0, identifier, arrayType, identifierLocation);
if (variable && symbol)
- {
symbol->setId(variable->getUniqueId());
- }
- return aggregate;
+ return intermediate.makeAggregate(symbol, identifierLocation);
}
-TIntermAggregate* TParseContext::parseSingleInitDeclaration(TPublicType &publicType, const TSourceLoc& identifierLocation, const TString &identifier, const TSourceLoc& initLocation, TIntermTyped *initializer)
+TIntermAggregate *TParseContext::parseSingleInitDeclaration(const TPublicType &publicType,
+ const TSourceLoc &identifierLocation,
+ const TString &identifier,
+ const TSourceLoc &initLocation,
+ TIntermTyped *initializer)
{
- if (singleDeclarationErrorCheck(publicType, identifierLocation, identifier))
+ mDeferredSingleDeclarationErrorCheck = false;
+
+ if (singleDeclarationErrorCheck(publicType, identifierLocation))
recover();
- TIntermNode* intermNode;
- if (!executeInitializer(identifierLocation, identifier, publicType, initializer, intermNode))
+ TIntermNode *intermNode = nullptr;
+ if (!executeInitializer(identifierLocation, identifier, publicType, initializer, &intermNode))
{
//
// Build intermediate representation
//
- return intermNode ? intermediate.makeAggregate(intermNode, initLocation) : NULL;
+ return intermNode ? intermediate.makeAggregate(intermNode, initLocation) : nullptr;
}
else
{
recover();
- return NULL;
+ return nullptr;
}
}
-TIntermAggregate* TParseContext::parseInvariantDeclaration(const TSourceLoc &invariantLoc,
+TIntermAggregate *TParseContext::parseSingleArrayInitDeclaration(
+ TPublicType &publicType,
+ const TSourceLoc &identifierLocation,
+ const TString &identifier,
+ const TSourceLoc &indexLocation,
+ TIntermTyped *indexExpression,
+ const TSourceLoc &initLocation,
+ TIntermTyped *initializer)
+{
+ mDeferredSingleDeclarationErrorCheck = false;
+
+ if (singleDeclarationErrorCheck(publicType, identifierLocation))
+ recover();
+
+ if (arrayTypeErrorCheck(indexLocation, publicType) ||
+ arrayQualifierErrorCheck(indexLocation, publicType))
+ {
+ recover();
+ }
+
+ TPublicType arrayType(publicType);
+
+ int size = 0;
+ // If indexExpression is nullptr, then the array will eventually get its size implicitly from
+ // the initializer.
+ if (indexExpression != nullptr &&
+ arraySizeErrorCheck(identifierLocation, indexExpression, size))
+ {
+ recover();
+ }
+ // Make the type an array even if size check failed.
+ // This ensures useless error messages regarding the variable's non-arrayness won't follow.
+ arrayType.setArraySize(size);
+
+ // initNode will correspond to the whole of "type b[n] = initializer".
+ TIntermNode *initNode = nullptr;
+ if (!executeInitializer(identifierLocation, identifier, arrayType, initializer, &initNode))
+ {
+ return initNode ? intermediate.makeAggregate(initNode, initLocation) : nullptr;
+ }
+ else
+ {
+ recover();
+ return nullptr;
+ }
+}
+
+TIntermAggregate *TParseContext::parseInvariantDeclaration(const TSourceLoc &invariantLoc,
const TSourceLoc &identifierLoc,
const TString *identifier,
const TSymbol *symbol)
@@ -1400,23 +1677,24 @@ TIntermAggregate* TParseContext::parseInvariantDeclaration(const TSourceLoc &inv
{
error(identifierLoc, "undeclared identifier declared as invariant", identifier->c_str());
recover();
- return NULL;
+ return nullptr;
}
else
{
const TString kGlFrontFacing("gl_FrontFacing");
if (*identifier == kGlFrontFacing)
{
- error(identifierLoc, "identifier should not be declared as invariant", identifier->c_str());
+ error(identifierLoc, "identifier should not be declared as invariant",
+ identifier->c_str());
recover();
- return NULL;
+ return nullptr;
}
symbolTable.addInvariantVarying(std::string(identifier->c_str()));
const TVariable *variable = getNamedVariable(identifierLoc, identifier, symbol);
ASSERT(variable);
const TType &type = variable->getType();
- TIntermSymbol *intermSymbol = intermediate.addSymbol(variable->getUniqueId(),
- *identifier, type, identifierLoc);
+ TIntermSymbol *intermSymbol =
+ intermediate.addSymbol(variable->getUniqueId(), *identifier, type, identifierLoc);
TIntermAggregate *aggregate = intermediate.makeAggregate(intermSymbol, identifierLoc);
aggregate->setOp(EOpInvariantDeclaration);
@@ -1424,98 +1702,189 @@ TIntermAggregate* TParseContext::parseInvariantDeclaration(const TSourceLoc &inv
}
}
-TIntermAggregate* TParseContext::parseDeclarator(TPublicType &publicType, TIntermAggregate *aggregateDeclaration, TSymbol *identifierSymbol, const TSourceLoc& identifierLocation, const TString &identifier)
+TIntermAggregate *TParseContext::parseDeclarator(TPublicType &publicType,
+ TIntermAggregate *aggregateDeclaration,
+ const TSourceLoc &identifierLocation,
+ const TString &identifier)
{
- TIntermSymbol* symbol = intermediate.addSymbol(0, identifier, TType(publicType), identifierLocation);
- TIntermAggregate* intermAggregate = intermediate.growAggregate(aggregateDeclaration, symbol, identifierLocation);
-
- if (structQualifierErrorCheck(identifierLocation, publicType))
- recover();
+ // If the declaration starting this declarator list was empty (example: int,), some checks were
+ // not performed.
+ if (mDeferredSingleDeclarationErrorCheck)
+ {
+ if (singleDeclarationErrorCheck(publicType, identifierLocation))
+ recover();
+ mDeferredSingleDeclarationErrorCheck = false;
+ }
if (locationDeclaratorListCheck(identifierLocation, publicType))
recover();
- if (nonInitConstErrorCheck(identifierLocation, identifier, publicType, false))
+ if (nonInitErrorCheck(identifierLocation, identifier, &publicType))
recover();
- TVariable* variable = 0;
- if (nonInitErrorCheck(identifierLocation, identifier, publicType, variable))
+ TVariable *variable = nullptr;
+ if (!declareVariable(identifierLocation, identifier, TType(publicType), &variable))
recover();
- if (symbol && variable)
+
+ TIntermSymbol *symbol =
+ intermediate.addSymbol(0, identifier, TType(publicType), identifierLocation);
+ if (variable && symbol)
symbol->setId(variable->getUniqueId());
- return intermAggregate;
+ return intermediate.growAggregate(aggregateDeclaration, symbol, identifierLocation);
}
-TIntermAggregate* TParseContext::parseArrayDeclarator(TPublicType &publicType, const TSourceLoc& identifierLocation, const TString &identifier, const TSourceLoc& arrayLocation, TIntermNode *declaratorList, TIntermTyped *indexExpression)
+TIntermAggregate *TParseContext::parseArrayDeclarator(TPublicType &publicType,
+ TIntermAggregate *aggregateDeclaration,
+ const TSourceLoc &identifierLocation,
+ const TString &identifier,
+ const TSourceLoc &arrayLocation,
+ TIntermTyped *indexExpression)
{
- if (structQualifierErrorCheck(identifierLocation, publicType))
- recover();
+ // If the declaration starting this declarator list was empty (example: int,), some checks were
+ // not performed.
+ if (mDeferredSingleDeclarationErrorCheck)
+ {
+ if (singleDeclarationErrorCheck(publicType, identifierLocation))
+ recover();
+ mDeferredSingleDeclarationErrorCheck = false;
+ }
if (locationDeclaratorListCheck(identifierLocation, publicType))
recover();
- if (nonInitConstErrorCheck(identifierLocation, identifier, publicType, true))
+ if (nonInitErrorCheck(identifierLocation, identifier, &publicType))
recover();
- if (arrayTypeErrorCheck(arrayLocation, publicType) || arrayQualifierErrorCheck(arrayLocation, publicType))
+ if (arrayTypeErrorCheck(arrayLocation, publicType) ||
+ arrayQualifierErrorCheck(arrayLocation, publicType))
{
recover();
}
- else if (indexExpression)
+ else
{
+ TType arrayType = TType(publicType);
int size;
if (arraySizeErrorCheck(arrayLocation, indexExpression, size))
+ {
recover();
- TPublicType arrayType(publicType);
- arrayType.setArray(true, size);
- TVariable* variable = NULL;
- if (arrayErrorCheck(arrayLocation, identifier, arrayType, variable))
- recover();
- TType type = TType(arrayType);
- type.setArraySize(size);
+ }
+ arrayType.setArraySize(size);
- return intermediate.growAggregate(declaratorList, intermediate.addSymbol(variable ? variable->getUniqueId() : 0, identifier, type, identifierLocation), identifierLocation);
- }
- else
- {
- TPublicType arrayType(publicType);
- arrayType.setArray(true);
- TVariable* variable = NULL;
- if (arrayErrorCheck(arrayLocation, identifier, arrayType, variable))
+ TVariable *variable = nullptr;
+ if (!declareVariable(identifierLocation, identifier, arrayType, &variable))
recover();
+
+ TIntermSymbol *symbol =
+ intermediate.addSymbol(0, identifier, arrayType, identifierLocation);
+ if (variable && symbol)
+ symbol->setId(variable->getUniqueId());
+
+ return intermediate.growAggregate(aggregateDeclaration, symbol, identifierLocation);
}
- return NULL;
+ return nullptr;
}
-TIntermAggregate* TParseContext::parseInitDeclarator(TPublicType &publicType, TIntermAggregate *declaratorList, const TSourceLoc& identifierLocation, const TString &identifier, const TSourceLoc& initLocation, TIntermTyped *initializer)
+TIntermAggregate *TParseContext::parseInitDeclarator(const TPublicType &publicType,
+ TIntermAggregate *aggregateDeclaration,
+ const TSourceLoc &identifierLocation,
+ const TString &identifier,
+ const TSourceLoc &initLocation,
+ TIntermTyped *initializer)
{
- if (structQualifierErrorCheck(identifierLocation, publicType))
- recover();
+ // If the declaration starting this declarator list was empty (example: int,), some checks were
+ // not performed.
+ if (mDeferredSingleDeclarationErrorCheck)
+ {
+ if (singleDeclarationErrorCheck(publicType, identifierLocation))
+ recover();
+ mDeferredSingleDeclarationErrorCheck = false;
+ }
if (locationDeclaratorListCheck(identifierLocation, publicType))
recover();
- TIntermNode* intermNode;
- if (!executeInitializer(identifierLocation, identifier, publicType, initializer, intermNode))
+ TIntermNode *intermNode = nullptr;
+ if (!executeInitializer(identifierLocation, identifier, publicType, initializer, &intermNode))
{
//
// build the intermediate representation
//
if (intermNode)
{
- return intermediate.growAggregate(declaratorList, intermNode, initLocation);
+ return intermediate.growAggregate(aggregateDeclaration, intermNode, initLocation);
}
else
{
- return declaratorList;
+ return aggregateDeclaration;
}
}
else
{
recover();
- return NULL;
+ return nullptr;
+ }
+}
+
+TIntermAggregate *TParseContext::parseArrayInitDeclarator(const TPublicType &publicType,
+ TIntermAggregate *aggregateDeclaration,
+ const TSourceLoc &identifierLocation,
+ const TString &identifier,
+ const TSourceLoc &indexLocation,
+ TIntermTyped *indexExpression,
+ const TSourceLoc &initLocation,
+ TIntermTyped *initializer)
+{
+ // If the declaration starting this declarator list was empty (example: int,), some checks were
+ // not performed.
+ if (mDeferredSingleDeclarationErrorCheck)
+ {
+ if (singleDeclarationErrorCheck(publicType, identifierLocation))
+ recover();
+ mDeferredSingleDeclarationErrorCheck = false;
+ }
+
+ if (locationDeclaratorListCheck(identifierLocation, publicType))
+ recover();
+
+ if (arrayTypeErrorCheck(indexLocation, publicType) ||
+ arrayQualifierErrorCheck(indexLocation, publicType))
+ {
+ recover();
+ }
+
+ TPublicType arrayType(publicType);
+
+ int size = 0;
+ // If indexExpression is nullptr, then the array will eventually get its size implicitly from
+ // the initializer.
+ if (indexExpression != nullptr &&
+ arraySizeErrorCheck(identifierLocation, indexExpression, size))
+ {
+ recover();
+ }
+ // Make the type an array even if size check failed.
+ // This ensures useless error messages regarding the variable's non-arrayness won't follow.
+ arrayType.setArraySize(size);
+
+ // initNode will correspond to the whole of "b[n] = initializer".
+ TIntermNode *initNode = nullptr;
+ if (!executeInitializer(identifierLocation, identifier, arrayType, initializer, &initNode))
+ {
+ if (initNode)
+ {
+ return intermediate.growAggregate(aggregateDeclaration, initNode, initLocation);
+ }
+ else
+ {
+ return aggregateDeclaration;
+ }
+ }
+ else
+ {
+ recover();
+ return nullptr;
}
}
@@ -1523,7 +1892,8 @@ void TParseContext::parseGlobalLayoutQualifier(const TPublicType &typeQualifier)
{
if (typeQualifier.qualifier != EvqUniform)
{
- error(typeQualifier.line, "invalid qualifier:", getQualifierString(typeQualifier.qualifier), "global layout must be uniform");
+ error(typeQualifier.line, "invalid qualifier:", getQualifierString(typeQualifier.qualifier),
+ "global layout must be uniform");
recover();
return;
}
@@ -1531,7 +1901,7 @@ void TParseContext::parseGlobalLayoutQualifier(const TPublicType &typeQualifier)
const TLayoutQualifier layoutQualifier = typeQualifier.layoutQualifier;
ASSERT(!layoutQualifier.isEmpty());
- if (shaderVersion < 300)
+ if (mShaderVersion < 300)
{
error(typeQualifier.line, "layout qualifiers supported in GLSL ES 3.00 only", "layout");
recover();
@@ -1546,17 +1916,269 @@ void TParseContext::parseGlobalLayoutQualifier(const TPublicType &typeQualifier)
if (layoutQualifier.matrixPacking != EmpUnspecified)
{
- defaultMatrixPacking = layoutQualifier.matrixPacking;
+ mDefaultMatrixPacking = layoutQualifier.matrixPacking;
}
if (layoutQualifier.blockStorage != EbsUnspecified)
{
- defaultBlockStorage = layoutQualifier.blockStorage;
+ mDefaultBlockStorage = layoutQualifier.blockStorage;
+ }
+}
+
+TIntermAggregate *TParseContext::addFunctionPrototypeDeclaration(const TFunction &function,
+ const TSourceLoc &location)
+{
+ // Note: symbolTableFunction could be the same as function if this is the first declaration.
+ // Either way the instance in the symbol table is used to track whether the function is declared
+ // multiple times.
+ TFunction *symbolTableFunction =
+ static_cast<TFunction *>(symbolTable.find(function.getMangledName(), getShaderVersion()));
+ if (symbolTableFunction->hasPrototypeDeclaration() && mShaderVersion == 100)
+ {
+ // ESSL 1.00.17 section 4.2.7.
+ // Doesn't apply to ESSL 3.00.4: see section 4.2.3.
+ error(location, "duplicate function prototype declarations are not allowed", "function");
+ recover();
+ }
+ symbolTableFunction->setHasPrototypeDeclaration();
+
+ TIntermAggregate *prototype = new TIntermAggregate;
+ prototype->setType(function.getReturnType());
+ prototype->setName(function.getMangledName());
+ prototype->setFunctionId(function.getUniqueId());
+
+ for (size_t i = 0; i < function.getParamCount(); i++)
+ {
+ const TConstParameter &param = function.getParam(i);
+ if (param.name != 0)
+ {
+ TVariable variable(param.name, *param.type);
+
+ TIntermSymbol *paramSymbol = intermediate.addSymbol(
+ variable.getUniqueId(), variable.getName(), variable.getType(), location);
+ prototype = intermediate.growAggregate(prototype, paramSymbol, location);
+ }
+ else
+ {
+ TIntermSymbol *paramSymbol = intermediate.addSymbol(0, "", *param.type, location);
+ prototype = intermediate.growAggregate(prototype, paramSymbol, location);
+ }
+ }
+
+ prototype->setOp(EOpPrototype);
+
+ symbolTable.pop();
+
+ if (!symbolTable.atGlobalLevel())
+ {
+ // ESSL 3.00.4 section 4.2.4.
+ error(location, "local function prototype declarations are not allowed", "function");
+ recover();
+ }
+
+ return prototype;
+}
+
+TIntermAggregate *TParseContext::addFunctionDefinition(const TFunction &function,
+ TIntermAggregate *functionPrototype,
+ TIntermAggregate *functionBody,
+ const TSourceLoc &location)
+{
+ //?? Check that all paths return a value if return type != void ?
+ // May be best done as post process phase on intermediate code
+ if (mCurrentFunctionType->getBasicType() != EbtVoid && !mFunctionReturnsValue)
+ {
+ error(location, "function does not return a value:", "", function.getName().c_str());
+ recover();
+ }
+
+ TIntermAggregate *aggregate =
+ intermediate.growAggregate(functionPrototype, functionBody, location);
+ intermediate.setAggregateOperator(aggregate, EOpFunction, location);
+ aggregate->setName(function.getMangledName().c_str());
+ aggregate->setType(function.getReturnType());
+ aggregate->setFunctionId(function.getUniqueId());
+
+ symbolTable.pop();
+ return aggregate;
+}
+
+void TParseContext::parseFunctionPrototype(const TSourceLoc &location,
+ TFunction *function,
+ TIntermAggregate **aggregateOut)
+{
+ const TSymbol *builtIn =
+ symbolTable.findBuiltIn(function->getMangledName(), getShaderVersion());
+
+ if (builtIn)
+ {
+ error(location, "built-in functions cannot be redefined", function->getName().c_str());
+ recover();
+ }
+
+ TFunction *prevDec =
+ static_cast<TFunction *>(symbolTable.find(function->getMangledName(), getShaderVersion()));
+ //
+ // Note: 'prevDec' could be 'function' if this is the first time we've seen function
+ // as it would have just been put in the symbol table. Otherwise, we're looking up
+ // an earlier occurance.
+ //
+ if (prevDec->isDefined())
+ {
+ // Then this function already has a body.
+ error(location, "function already has a body", function->getName().c_str());
+ recover();
+ }
+ prevDec->setDefined();
+ //
+ // Overload the unique ID of the definition to be the same unique ID as the declaration.
+ // Eventually we will probably want to have only a single definition and just swap the
+ // arguments to be the definition's arguments.
+ //
+ function->setUniqueId(prevDec->getUniqueId());
+
+ // Raise error message if main function takes any parameters or return anything other than void
+ if (function->getName() == "main")
+ {
+ if (function->getParamCount() > 0)
+ {
+ error(location, "function cannot take any parameter(s)", function->getName().c_str());
+ recover();
+ }
+ if (function->getReturnType().getBasicType() != EbtVoid)
+ {
+ error(location, "", function->getReturnType().getBasicString(),
+ "main function cannot return a value");
+ recover();
+ }
+ }
+
+ //
+ // Remember the return type for later checking for RETURN statements.
+ //
+ mCurrentFunctionType = &(prevDec->getReturnType());
+ mFunctionReturnsValue = false;
+
+ //
+ // Insert parameters into the symbol table.
+ // If the parameter has no name, it's not an error, just don't insert it
+ // (could be used for unused args).
+ //
+ // Also, accumulate the list of parameters into the HIL, so lower level code
+ // knows where to find parameters.
+ //
+ TIntermAggregate *paramNodes = new TIntermAggregate;
+ for (size_t i = 0; i < function->getParamCount(); i++)
+ {
+ const TConstParameter &param = function->getParam(i);
+ if (param.name != 0)
+ {
+ TVariable *variable = new TVariable(param.name, *param.type);
+ //
+ // Insert the parameters with name in the symbol table.
+ //
+ if (!symbolTable.declare(variable))
+ {
+ error(location, "redefinition", variable->getName().c_str());
+ recover();
+ paramNodes = intermediate.growAggregate(
+ paramNodes, intermediate.addSymbol(0, "", *param.type, location), location);
+ continue;
+ }
+
+ //
+ // Add the parameter to the HIL
+ //
+ TIntermSymbol *symbol = intermediate.addSymbol(
+ variable->getUniqueId(), variable->getName(), variable->getType(), location);
+
+ paramNodes = intermediate.growAggregate(paramNodes, symbol, location);
+ }
+ else
+ {
+ paramNodes = intermediate.growAggregate(
+ paramNodes, intermediate.addSymbol(0, "", *param.type, location), location);
+ }
+ }
+ intermediate.setAggregateOperator(paramNodes, EOpParameters, location);
+ *aggregateOut = paramNodes;
+ setLoopNestingLevel(0);
+}
+
+TFunction *TParseContext::parseFunctionDeclarator(const TSourceLoc &location, TFunction *function)
+{
+ //
+ // We don't know at this point whether this is a function definition or a prototype.
+ // The definition production code will check for redefinitions.
+ // In the case of ESSL 1.00 the prototype production code will also check for redeclarations.
+ //
+ // Return types and parameter qualifiers must match in all redeclarations, so those are checked
+ // here.
+ //
+ TFunction *prevDec =
+ static_cast<TFunction *>(symbolTable.find(function->getMangledName(), getShaderVersion()));
+ if (prevDec)
+ {
+ if (prevDec->getReturnType() != function->getReturnType())
+ {
+ error(location, "overloaded functions must have the same return type",
+ function->getReturnType().getBasicString());
+ recover();
+ }
+ for (size_t i = 0; i < prevDec->getParamCount(); ++i)
+ {
+ if (prevDec->getParam(i).type->getQualifier() !=
+ function->getParam(i).type->getQualifier())
+ {
+ error(location, "overloaded functions must have the same parameter qualifiers",
+ function->getParam(i).type->getQualifierString());
+ recover();
+ }
+ }
+ }
+
+ //
+ // Check for previously declared variables using the same name.
+ //
+ TSymbol *prevSym = symbolTable.find(function->getName(), getShaderVersion());
+ if (prevSym)
+ {
+ if (!prevSym->isFunction())
+ {
+ error(location, "redefinition", function->getName().c_str(), "function");
+ recover();
+ }
+ }
+ else
+ {
+ // Insert the unmangled name to detect potential future redefinition as a variable.
+ TFunction *newFunction =
+ new TFunction(NewPoolTString(function->getName().c_str()), &function->getReturnType());
+ symbolTable.getOuterLevel()->insertUnmangled(newFunction);
}
+
+ // We're at the inner scope level of the function's arguments and body statement.
+ // Add the function prototype to the surrounding scope instead.
+ symbolTable.getOuterLevel()->insert(function);
+
+ //
+ // If this is a redeclaration, it could also be a definition, in which case, we want to use the
+ // variable names from this one, and not the one that's
+ // being redeclared. So, pass back up this declaration, not the one in the symbol table.
+ //
+ return function;
}
-TFunction *TParseContext::addConstructorFunc(TPublicType publicType)
+TFunction *TParseContext::addConstructorFunc(const TPublicType &publicTypeIn)
{
+ TPublicType publicType = publicTypeIn;
+ if (publicType.isStructSpecifier)
+ {
+ error(publicType.line, "constructor can't be a structure definition",
+ getBasicString(publicType.type));
+ recover();
+ }
+
TOperator op = EOpNull;
if (publicType.userDef)
{
@@ -1566,60 +2188,131 @@ TFunction *TParseContext::addConstructorFunc(TPublicType publicType)
{
switch (publicType.type)
{
- case EbtFloat:
- if (publicType.isMatrix())
- {
- // TODO: non-square matrices
- switch(publicType.getCols())
+ case EbtFloat:
+ if (publicType.isMatrix())
{
- case 2: op = EOpConstructMat2; break;
- case 3: op = EOpConstructMat3; break;
- case 4: op = EOpConstructMat4; break;
+ switch (publicType.getCols())
+ {
+ case 2:
+ switch (publicType.getRows())
+ {
+ case 2:
+ op = EOpConstructMat2;
+ break;
+ case 3:
+ op = EOpConstructMat2x3;
+ break;
+ case 4:
+ op = EOpConstructMat2x4;
+ break;
+ }
+ break;
+ case 3:
+ switch (publicType.getRows())
+ {
+ case 2:
+ op = EOpConstructMat3x2;
+ break;
+ case 3:
+ op = EOpConstructMat3;
+ break;
+ case 4:
+ op = EOpConstructMat3x4;
+ break;
+ }
+ break;
+ case 4:
+ switch (publicType.getRows())
+ {
+ case 2:
+ op = EOpConstructMat4x2;
+ break;
+ case 3:
+ op = EOpConstructMat4x3;
+ break;
+ case 4:
+ op = EOpConstructMat4;
+ break;
+ }
+ break;
+ }
}
- }
- else
- {
- switch(publicType.getNominalSize())
+ else
{
- case 1: op = EOpConstructFloat; break;
- case 2: op = EOpConstructVec2; break;
- case 3: op = EOpConstructVec3; break;
- case 4: op = EOpConstructVec4; break;
+ switch (publicType.getNominalSize())
+ {
+ case 1:
+ op = EOpConstructFloat;
+ break;
+ case 2:
+ op = EOpConstructVec2;
+ break;
+ case 3:
+ op = EOpConstructVec3;
+ break;
+ case 4:
+ op = EOpConstructVec4;
+ break;
+ }
}
- }
- break;
+ break;
- case EbtInt:
- switch(publicType.getNominalSize())
- {
- case 1: op = EOpConstructInt; break;
- case 2: op = EOpConstructIVec2; break;
- case 3: op = EOpConstructIVec3; break;
- case 4: op = EOpConstructIVec4; break;
- }
- break;
+ case EbtInt:
+ switch (publicType.getNominalSize())
+ {
+ case 1:
+ op = EOpConstructInt;
+ break;
+ case 2:
+ op = EOpConstructIVec2;
+ break;
+ case 3:
+ op = EOpConstructIVec3;
+ break;
+ case 4:
+ op = EOpConstructIVec4;
+ break;
+ }
+ break;
- case EbtUInt:
- switch(publicType.getNominalSize())
- {
- case 1: op = EOpConstructUInt; break;
- case 2: op = EOpConstructUVec2; break;
- case 3: op = EOpConstructUVec3; break;
- case 4: op = EOpConstructUVec4; break;
- }
- break;
+ case EbtUInt:
+ switch (publicType.getNominalSize())
+ {
+ case 1:
+ op = EOpConstructUInt;
+ break;
+ case 2:
+ op = EOpConstructUVec2;
+ break;
+ case 3:
+ op = EOpConstructUVec3;
+ break;
+ case 4:
+ op = EOpConstructUVec4;
+ break;
+ }
+ break;
- case EbtBool:
- switch(publicType.getNominalSize())
- {
- case 1: op = EOpConstructBool; break;
- case 2: op = EOpConstructBVec2; break;
- case 3: op = EOpConstructBVec3; break;
- case 4: op = EOpConstructBVec4; break;
- }
- break;
+ case EbtBool:
+ switch (publicType.getNominalSize())
+ {
+ case 1:
+ op = EOpConstructBool;
+ break;
+ case 2:
+ op = EOpConstructBVec2;
+ break;
+ case 3:
+ op = EOpConstructBVec3;
+ break;
+ case 4:
+ op = EOpConstructBVec4;
+ break;
+ }
+ break;
- default: break;
+ default:
+ break;
}
if (op == EOpNull)
@@ -1627,40 +2320,58 @@ TFunction *TParseContext::addConstructorFunc(TPublicType publicType)
error(publicType.line, "cannot construct this type", getBasicString(publicType.type));
recover();
publicType.type = EbtFloat;
- op = EOpConstructFloat;
+ op = EOpConstructFloat;
}
}
TString tempString;
- TType type(publicType);
+ const TType *type = new TType(publicType);
return new TFunction(&tempString, type, op);
}
-// This function is used to test for the correctness of the parameters passed to various constructor functions
-// and also convert them to the right datatype if it is allowed and required.
+// This function is used to test for the correctness of the parameters passed to various constructor
+// functions and also convert them to the right datatype if it is allowed and required.
//
// Returns 0 for an error or the constructed node (aggregate or typed) for no error.
//
-TIntermTyped *TParseContext::addConstructor(TIntermNode *arguments, TType *type, TOperator op, TFunction *fnCall, const TSourceLoc &line)
+TIntermTyped *TParseContext::addConstructor(TIntermNode *arguments,
+ TType *type,
+ TOperator op,
+ TFunction *fnCall,
+ const TSourceLoc &line)
{
- TIntermAggregate *aggregateArguments = arguments->getAsAggregate();
+ TIntermAggregate *constructor = arguments->getAsAggregate();
+ ASSERT(constructor != nullptr);
- if (!aggregateArguments)
+ if (type->isArray())
{
- aggregateArguments = new TIntermAggregate;
- aggregateArguments->getSequence()->push_back(arguments);
+ // GLSL ES 3.00 section 5.4.4: Each argument must be the same type as the element type of
+ // the array.
+ TIntermSequence *args = constructor->getSequence();
+ for (size_t i = 0; i < args->size(); i++)
+ {
+ const TType &argType = (*args)[i]->getAsTyped()->getType();
+ // It has already been checked that the argument is not an array.
+ ASSERT(!argType.isArray());
+ if (!argType.sameElementType(*type))
+ {
+ error(line, "Array constructor argument has an incorrect type", "Error");
+ recover();
+ return nullptr;
+ }
+ }
}
-
- if (op == EOpConstructStruct)
+ else if (op == EOpConstructStruct)
{
const TFieldList &fields = type->getStruct()->fields();
- TIntermSequence *args = aggregateArguments->getSequence();
+ TIntermSequence *args = constructor->getSequence();
for (size_t i = 0; i < fields.size(); i++)
{
if (i >= args->size() || (*args)[i]->getAsTyped()->getType() != *fields[i]->type())
{
- error(line, "Structure constructor arguments do not match structure fields", "Error");
+ error(line, "Structure constructor arguments do not match structure fields",
+ "Error");
recover();
return 0;
@@ -1669,12 +2380,12 @@ TIntermTyped *TParseContext::addConstructor(TIntermNode *arguments, TType *type,
}
// Turn the argument list itself into a constructor
- TIntermAggregate *constructor = intermediate.setAggregateOperator(aggregateArguments, op, line);
- TIntermTyped *constConstructor = foldConstConstructor(constructor, *type);
- if (constConstructor)
- {
- return constConstructor;
- }
+ constructor->setOp(op);
+ constructor->setLine(line);
+ ASSERT(constructor->isConstructor());
+
+ // Need to set type before setPrecisionFromChildren() because bool doesn't have precision.
+ constructor->setType(*type);
// Structs should not be precision qualified, the individual members may be.
// Built-in types on the other hand should be precision qualified.
@@ -1684,173 +2395,142 @@ TIntermTyped *TParseContext::addConstructor(TIntermNode *arguments, TType *type,
type->setPrecision(constructor->getPrecision());
}
- return constructor;
-}
-
-TIntermTyped* TParseContext::foldConstConstructor(TIntermAggregate* aggrNode, const TType& type)
-{
- bool canBeFolded = areAllChildConst(aggrNode);
- aggrNode->setType(type);
- if (canBeFolded) {
- bool returnVal = false;
- ConstantUnion* unionArray = new ConstantUnion[type.getObjectSize()];
- if (aggrNode->getSequence()->size() == 1) {
- returnVal = intermediate.parseConstTree(aggrNode->getLine(), aggrNode, unionArray, aggrNode->getOp(), type, true);
- }
- else {
- returnVal = intermediate.parseConstTree(aggrNode->getLine(), aggrNode, unionArray, aggrNode->getOp(), type);
- }
- if (returnVal)
- return 0;
-
- return intermediate.addConstantUnion(unionArray, type, aggrNode->getLine());
+ TIntermTyped *constConstructor = intermediate.foldAggregateBuiltIn(constructor);
+ if (constConstructor)
+ {
+ return constConstructor;
}
- return 0;
+ return constructor;
}
//
-// This function returns the tree representation for the vector field(s) being accessed from contant vector.
-// If only one component of vector is accessed (v.x or v[0] where v is a contant vector), then a contant node is
-// returned, else an aggregate node is returned (for v.xy). The input to this function could either be the symbol
-// node or it could be the intermediate tree representation of accessing fields in a constant structure or column of
-// a constant matrix.
+// This function returns the tree representation for the vector field(s) being accessed from contant
+// vector.
+// If only one component of vector is accessed (v.x or v[0] where v is a contant vector), then a
+// contant node is returned, else an aggregate node is returned (for v.xy). The input to this
+// function could either be the symbol node or it could be the intermediate tree representation of
+// accessing fields in a constant structure or column of a constant matrix.
//
-TIntermTyped* TParseContext::addConstVectorNode(TVectorFields& fields, TIntermTyped* node, const TSourceLoc& line)
+TIntermTyped *TParseContext::addConstVectorNode(TVectorFields &fields,
+ TIntermConstantUnion *node,
+ const TSourceLoc &line,
+ bool outOfRangeIndexIsError)
{
- TIntermTyped* typedNode;
- TIntermConstantUnion* tempConstantNode = node->getAsConstantUnion();
-
- ConstantUnion *unionArray;
- if (tempConstantNode) {
- unionArray = tempConstantNode->getUnionArrayPointer();
-
- if (!unionArray) {
- return node;
- }
- } else { // The node has to be either a symbol node or an aggregate node or a tempConstant node, else, its an error
- error(line, "Cannot offset into the vector", "Error");
- recover();
-
- return 0;
- }
+ const TConstantUnion *unionArray = node->getUnionArrayPointer();
+ ASSERT(unionArray);
- ConstantUnion* constArray = new ConstantUnion[fields.num];
+ TConstantUnion *constArray = new TConstantUnion[fields.num];
- for (int i = 0; i < fields.num; i++) {
- if (fields.offsets[i] >= node->getType().getNominalSize()) {
+ for (int i = 0; i < fields.num; i++)
+ {
+ if (fields.offsets[i] >= node->getType().getNominalSize())
+ {
std::stringstream extraInfoStream;
extraInfoStream << "vector field selection out of range '" << fields.offsets[i] << "'";
std::string extraInfo = extraInfoStream.str();
- error(line, "", "[", extraInfo.c_str());
- recover();
- fields.offsets[i] = 0;
+ outOfRangeError(outOfRangeIndexIsError, line, "", "[", extraInfo.c_str());
+ fields.offsets[i] = node->getType().getNominalSize() - 1;
}
-
- constArray[i] = unionArray[fields.offsets[i]];
- }
- typedNode = intermediate.addConstantUnion(constArray, node->getType(), line);
- return typedNode;
+ constArray[i] = unionArray[fields.offsets[i]];
+ }
+ return intermediate.addConstantUnion(constArray, node->getType(), line);
}
//
-// This function returns the column being accessed from a constant matrix. The values are retrieved from
-// the symbol table and parse-tree is built for a vector (each column of a matrix is a vector). The input
-// to the function could either be a symbol node (m[0] where m is a constant matrix)that represents a
-// constant matrix or it could be the tree representation of the constant matrix (s.m1[0] where s is a constant structure)
+// This function returns the column being accessed from a constant matrix. The values are retrieved
+// from the symbol table and parse-tree is built for a vector (each column of a matrix is a vector).
+// The input to the function could either be a symbol node (m[0] where m is a constant matrix)that
+// represents a constant matrix or it could be the tree representation of the constant matrix
+// (s.m1[0] where s is a constant structure)
//
-TIntermTyped* TParseContext::addConstMatrixNode(int index, TIntermTyped* node, const TSourceLoc& line)
+TIntermTyped *TParseContext::addConstMatrixNode(int index,
+ TIntermConstantUnion *node,
+ const TSourceLoc &line,
+ bool outOfRangeIndexIsError)
{
- TIntermTyped* typedNode;
- TIntermConstantUnion* tempConstantNode = node->getAsConstantUnion();
-
- if (index >= node->getType().getCols()) {
+ if (index >= node->getType().getCols())
+ {
std::stringstream extraInfoStream;
extraInfoStream << "matrix field selection out of range '" << index << "'";
std::string extraInfo = extraInfoStream.str();
- error(line, "", "[", extraInfo.c_str());
- recover();
- index = 0;
+ outOfRangeError(outOfRangeIndexIsError, line, "", "[", extraInfo.c_str());
+ index = node->getType().getCols() - 1;
}
- if (tempConstantNode) {
- ConstantUnion* unionArray = tempConstantNode->getUnionArrayPointer();
- int size = tempConstantNode->getType().getCols();
- typedNode = intermediate.addConstantUnion(&unionArray[size*index], tempConstantNode->getType(), line);
- } else {
- error(line, "Cannot offset into the matrix", "Error");
- recover();
-
- return 0;
- }
-
- return typedNode;
+ const TConstantUnion *unionArray = node->getUnionArrayPointer();
+ int size = node->getType().getCols();
+ return intermediate.addConstantUnion(&unionArray[size * index], node->getType(), line);
}
-
//
-// This function returns an element of an array accessed from a constant array. The values are retrieved from
-// the symbol table and parse-tree is built for the type of the element. The input
-// to the function could either be a symbol node (a[0] where a is a constant array)that represents a
-// constant array or it could be the tree representation of the constant array (s.a1[0] where s is a constant structure)
+// This function returns an element of an array accessed from a constant array. The values are
+// retrieved from the symbol table and parse-tree is built for the type of the element. The input
+// to the function could either be a symbol node (a[0] where a is a constant array)that represents a
+// constant array or it could be the tree representation of the constant array (s.a1[0] where s is a
+// constant structure)
//
-TIntermTyped* TParseContext::addConstArrayNode(int index, TIntermTyped* node, const TSourceLoc& line)
+TIntermTyped *TParseContext::addConstArrayNode(int index,
+ TIntermConstantUnion *node,
+ const TSourceLoc &line,
+ bool outOfRangeIndexIsError)
{
- TIntermTyped* typedNode;
- TIntermConstantUnion* tempConstantNode = node->getAsConstantUnion();
TType arrayElementType = node->getType();
arrayElementType.clearArrayness();
- if (index >= node->getType().getArraySize()) {
+ if (index >= node->getType().getArraySize())
+ {
std::stringstream extraInfoStream;
extraInfoStream << "array field selection out of range '" << index << "'";
std::string extraInfo = extraInfoStream.str();
- error(line, "", "[", extraInfo.c_str());
- recover();
- index = 0;
- }
-
- if (tempConstantNode) {
- size_t arrayElementSize = arrayElementType.getObjectSize();
- ConstantUnion* unionArray = tempConstantNode->getUnionArrayPointer();
- typedNode = intermediate.addConstantUnion(&unionArray[arrayElementSize * index], tempConstantNode->getType(), line);
- } else {
- error(line, "Cannot offset into the array", "Error");
- recover();
-
- return 0;
+ outOfRangeError(outOfRangeIndexIsError, line, "", "[", extraInfo.c_str());
+ index = node->getType().getArraySize() - 1;
}
-
- return typedNode;
+ size_t arrayElementSize = arrayElementType.getObjectSize();
+ const TConstantUnion *unionArray = node->getUnionArrayPointer();
+ return intermediate.addConstantUnion(&unionArray[arrayElementSize * index], node->getType(),
+ line);
}
-
//
-// This function returns the value of a particular field inside a constant structure from the symbol table.
-// If there is an embedded/nested struct, it appropriately calls addConstStructNested or addConstStructFromAggr
-// function and returns the parse-tree with the values of the embedded/nested struct.
+// This function returns the value of a particular field inside a constant structure from the symbol
+// table.
+// If there is an embedded/nested struct, it appropriately calls addConstStructNested or
+// addConstStructFromAggr function and returns the parse-tree with the values of the embedded/nested
+// struct.
//
-TIntermTyped* TParseContext::addConstStruct(const TString &identifier, TIntermTyped *node, const TSourceLoc& line)
+TIntermTyped *TParseContext::addConstStruct(const TString &identifier,
+ TIntermTyped *node,
+ const TSourceLoc &line)
{
- const TFieldList& fields = node->getType().getStruct()->fields();
- size_t instanceSize = 0;
+ const TFieldList &fields = node->getType().getStruct()->fields();
+ size_t instanceSize = 0;
- for (size_t index = 0; index < fields.size(); ++index) {
- if (fields[index]->name() == identifier) {
+ for (size_t index = 0; index < fields.size(); ++index)
+ {
+ if (fields[index]->name() == identifier)
+ {
break;
- } else {
+ }
+ else
+ {
instanceSize += fields[index]->type()->getObjectSize();
}
}
TIntermTyped *typedNode;
TIntermConstantUnion *tempConstantNode = node->getAsConstantUnion();
- if (tempConstantNode) {
- ConstantUnion* constArray = tempConstantNode->getUnionArrayPointer();
+ if (tempConstantNode)
+ {
+ const TConstantUnion *constArray = tempConstantNode->getUnionArrayPointer();
- typedNode = intermediate.addConstantUnion(constArray+instanceSize, tempConstantNode->getType(), line); // type will be changed in the calling function
- } else {
+ // type will be changed in the calling function
+ typedNode = intermediate.addConstantUnion(constArray + instanceSize,
+ tempConstantNode->getType(), line);
+ }
+ else
+ {
error(line, "Cannot offset into the structure", "Error");
recover();
@@ -1863,15 +2543,22 @@ TIntermTyped* TParseContext::addConstStruct(const TString &identifier, TIntermTy
//
// Interface/uniform blocks
//
-TIntermAggregate* TParseContext::addInterfaceBlock(const TPublicType& typeQualifier, const TSourceLoc& nameLine, const TString& blockName, TFieldList* fieldList,
- const TString* instanceName, const TSourceLoc& instanceLine, TIntermTyped* arrayIndex, const TSourceLoc& arrayIndexLine)
+TIntermAggregate *TParseContext::addInterfaceBlock(const TPublicType &typeQualifier,
+ const TSourceLoc &nameLine,
+ const TString &blockName,
+ TFieldList *fieldList,
+ const TString *instanceName,
+ const TSourceLoc &instanceLine,
+ TIntermTyped *arrayIndex,
+ const TSourceLoc &arrayIndexLine)
{
if (reservedErrorCheck(nameLine, blockName))
recover();
if (typeQualifier.qualifier != EvqUniform)
{
- error(typeQualifier.line, "invalid qualifier:", getQualifierString(typeQualifier.qualifier), "interface blocks must be uniform");
+ error(typeQualifier.line, "invalid qualifier:", getQualifierString(typeQualifier.qualifier),
+ "interface blocks must be uniform");
recover();
}
@@ -1883,39 +2570,44 @@ TIntermAggregate* TParseContext::addInterfaceBlock(const TPublicType& typeQualif
if (blockLayoutQualifier.matrixPacking == EmpUnspecified)
{
- blockLayoutQualifier.matrixPacking = defaultMatrixPacking;
+ blockLayoutQualifier.matrixPacking = mDefaultMatrixPacking;
}
if (blockLayoutQualifier.blockStorage == EbsUnspecified)
{
- blockLayoutQualifier.blockStorage = defaultBlockStorage;
+ blockLayoutQualifier.blockStorage = mDefaultBlockStorage;
}
- TSymbol* blockNameSymbol = new TInterfaceBlockName(&blockName);
- if (!symbolTable.declare(blockNameSymbol)) {
+ TSymbol *blockNameSymbol = new TInterfaceBlockName(&blockName);
+ if (!symbolTable.declare(blockNameSymbol))
+ {
error(nameLine, "redefinition", blockName.c_str(), "interface block name");
recover();
}
// check for sampler types and apply layout qualifiers
- for (size_t memberIndex = 0; memberIndex < fieldList->size(); ++memberIndex) {
- TField* field = (*fieldList)[memberIndex];
- TType* fieldType = field->type();
- if (IsSampler(fieldType->getBasicType())) {
- error(field->line(), "unsupported type", fieldType->getBasicString(), "sampler types are not allowed in interface blocks");
+ for (size_t memberIndex = 0; memberIndex < fieldList->size(); ++memberIndex)
+ {
+ TField *field = (*fieldList)[memberIndex];
+ TType *fieldType = field->type();
+ if (IsSampler(fieldType->getBasicType()))
+ {
+ error(field->line(), "unsupported type", fieldType->getBasicString(),
+ "sampler types are not allowed in interface blocks");
recover();
}
const TQualifier qualifier = fieldType->getQualifier();
switch (qualifier)
{
- case EvqGlobal:
- case EvqUniform:
- break;
- default:
- error(field->line(), "invalid qualifier on interface block member", getQualifierString(qualifier));
- recover();
- break;
+ case EvqGlobal:
+ case EvqUniform:
+ break;
+ default:
+ error(field->line(), "invalid qualifier on interface block member",
+ getQualifierString(qualifier));
+ recover();
+ break;
}
// check layout qualifiers
@@ -1927,7 +2619,8 @@ TIntermAggregate* TParseContext::addInterfaceBlock(const TPublicType& typeQualif
if (fieldLayoutQualifier.blockStorage != EbsUnspecified)
{
- error(field->line(), "invalid layout qualifier:", getBlockStorageString(fieldLayoutQualifier.blockStorage), "cannot be used here");
+ error(field->line(), "invalid layout qualifier:",
+ getBlockStorageString(fieldLayoutQualifier.blockStorage), "cannot be used here");
recover();
}
@@ -1935,10 +2628,11 @@ TIntermAggregate* TParseContext::addInterfaceBlock(const TPublicType& typeQualif
{
fieldLayoutQualifier.matrixPacking = blockLayoutQualifier.matrixPacking;
}
- else if (!fieldType->isMatrix())
+ else if (!fieldType->isMatrix() && fieldType->getBasicType() != EbtStruct)
{
- error(field->line(), "invalid layout qualifier:", getMatrixPackingString(fieldLayoutQualifier.matrixPacking), "can only be used on matrix types");
- recover();
+ warning(field->line(), "extraneous layout qualifier:",
+ getMatrixPackingString(fieldLayoutQualifier.matrixPacking),
+ "only has an effect on matrix types");
}
fieldType->setLayoutQualifier(fieldLayoutQualifier);
@@ -1952,62 +2646,74 @@ TIntermAggregate* TParseContext::addInterfaceBlock(const TPublicType& typeQualif
recover();
}
- TInterfaceBlock* interfaceBlock = new TInterfaceBlock(&blockName, fieldList, instanceName, arraySize, blockLayoutQualifier);
- TType interfaceBlockType(interfaceBlock, typeQualifier.qualifier, blockLayoutQualifier, arraySize);
+ TInterfaceBlock *interfaceBlock =
+ new TInterfaceBlock(&blockName, fieldList, instanceName, arraySize, blockLayoutQualifier);
+ TType interfaceBlockType(interfaceBlock, typeQualifier.qualifier, blockLayoutQualifier,
+ arraySize);
TString symbolName = "";
- int symbolId = 0;
+ int symbolId = 0;
if (!instanceName)
{
// define symbols for the members of the interface block
for (size_t memberIndex = 0; memberIndex < fieldList->size(); ++memberIndex)
{
- TField* field = (*fieldList)[memberIndex];
- TType* fieldType = field->type();
+ TField *field = (*fieldList)[memberIndex];
+ TType *fieldType = field->type();
// set parent pointer of the field variable
fieldType->setInterfaceBlock(interfaceBlock);
- TVariable* fieldVariable = new TVariable(&field->name(), *fieldType);
+ TVariable *fieldVariable = new TVariable(&field->name(), *fieldType);
fieldVariable->setQualifier(typeQualifier.qualifier);
- if (!symbolTable.declare(fieldVariable)) {
- error(field->line(), "redefinition", field->name().c_str(), "interface block member name");
+ if (!symbolTable.declare(fieldVariable))
+ {
+ error(field->line(), "redefinition", field->name().c_str(),
+ "interface block member name");
recover();
}
}
}
else
{
+ if (reservedErrorCheck(instanceLine, *instanceName))
+ recover();
+
// add a symbol for this interface block
- TVariable* instanceTypeDef = new TVariable(instanceName, interfaceBlockType, false);
+ TVariable *instanceTypeDef = new TVariable(instanceName, interfaceBlockType, false);
instanceTypeDef->setQualifier(typeQualifier.qualifier);
- if (!symbolTable.declare(instanceTypeDef)) {
- error(instanceLine, "redefinition", instanceName->c_str(), "interface block instance name");
+ if (!symbolTable.declare(instanceTypeDef))
+ {
+ error(instanceLine, "redefinition", instanceName->c_str(),
+ "interface block instance name");
recover();
}
- symbolId = instanceTypeDef->getUniqueId();
+ symbolId = instanceTypeDef->getUniqueId();
symbolName = instanceTypeDef->getName();
}
- TIntermAggregate *aggregate = intermediate.makeAggregate(intermediate.addSymbol(symbolId, symbolName, interfaceBlockType, typeQualifier.line), nameLine);
+ TIntermAggregate *aggregate = intermediate.makeAggregate(
+ intermediate.addSymbol(symbolId, symbolName, interfaceBlockType, typeQualifier.line),
+ nameLine);
aggregate->setOp(EOpDeclaration);
exitStructDeclaration();
return aggregate;
}
-bool TParseContext::enterStructDeclaration(const TSourceLoc& line, const TString& identifier)
+bool TParseContext::enterStructDeclaration(const TSourceLoc &line, const TString &identifier)
{
- ++structNestingLevel;
+ ++mStructNestingLevel;
// Embedded structure definitions are not supported per GLSL ES spec.
// They aren't allowed in GLSL either, but we need to detect this here
// so we don't rely on the GLSL compiler to catch it.
- if (structNestingLevel > 1) {
+ if (mStructNestingLevel > 1)
+ {
error(line, "", "Embedded struct definitions are not allowed");
return true;
}
@@ -2017,33 +2723,34 @@ bool TParseContext::enterStructDeclaration(const TSourceLoc& line, const TString
void TParseContext::exitStructDeclaration()
{
- --structNestingLevel;
+ --mStructNestingLevel;
}
-namespace {
-
+namespace
+{
const int kWebGLMaxStructNesting = 4;
} // namespace
-bool TParseContext::structNestingErrorCheck(const TSourceLoc& line, const TField& field)
+bool TParseContext::structNestingErrorCheck(const TSourceLoc &line, const TField &field)
{
- if (!IsWebGLBasedSpec(shaderSpec)) {
+ if (!IsWebGLBasedSpec(mShaderSpec))
+ {
return false;
}
- if (field.type()->getBasicType() != EbtStruct) {
+ if (field.type()->getBasicType() != EbtStruct)
+ {
return false;
}
// We're already inside a structure definition at this point, so add
// one to the field's struct nesting.
- if (1 + field.type()->getDeepestStructNesting() > kWebGLMaxStructNesting) {
+ if (1 + field.type()->getDeepestStructNesting() > kWebGLMaxStructNesting)
+ {
std::stringstream reasonStream;
- reasonStream << "Reference of struct type "
- << field.type()->getStruct()->name().c_str()
- << " exceeds maximum allowed nesting level of "
- << kWebGLMaxStructNesting;
+ reasonStream << "Reference of struct type " << field.type()->getStruct()->name().c_str()
+ << " exceeds maximum allowed nesting level of " << kWebGLMaxStructNesting;
std::string reason = reasonStream.str();
error(line, reason.c_str(), field.name().c_str(), "");
return true;
@@ -2055,7 +2762,9 @@ bool TParseContext::structNestingErrorCheck(const TSourceLoc& line, const TField
//
// Parse an array index expression
//
-TIntermTyped* TParseContext::addIndexExpression(TIntermTyped *baseExpression, const TSourceLoc& location, TIntermTyped *indexExpression)
+TIntermTyped *TParseContext::addIndexExpression(TIntermTyped *baseExpression,
+ const TSourceLoc &location,
+ TIntermTyped *indexExpression)
{
TIntermTyped *indexedExpression = NULL;
@@ -2063,7 +2772,8 @@ TIntermTyped* TParseContext::addIndexExpression(TIntermTyped *baseExpression, co
{
if (baseExpression->getAsSymbolNode())
{
- error(location, " left of '[' is not of type array, matrix, or vector ", baseExpression->getAsSymbolNode()->getSymbol().c_str());
+ error(location, " left of '[' is not of type array, matrix, or vector ",
+ baseExpression->getAsSymbolNode()->getSymbol().c_str());
}
else
{
@@ -2074,137 +2784,188 @@ TIntermTyped* TParseContext::addIndexExpression(TIntermTyped *baseExpression, co
TIntermConstantUnion *indexConstantUnion = indexExpression->getAsConstantUnion();
- if (indexExpression->getQualifier() == EvqConst && indexConstantUnion)
+ // TODO(oetuaho@nvidia.com): Get rid of indexConstantUnion == nullptr below once ANGLE is able
+ // to constant fold all constant expressions. Right now we don't allow indexing interface blocks
+ // or fragment outputs with expressions that ANGLE is not able to constant fold, even if the
+ // index is a constant expression.
+ if (indexExpression->getQualifier() != EvqConst || indexConstantUnion == nullptr)
+ {
+ if (baseExpression->isInterfaceBlock())
+ {
+ error(
+ location, "", "[",
+ "array indexes for interface blocks arrays must be constant integral expressions");
+ recover();
+ }
+ else if (baseExpression->getQualifier() == EvqFragmentOut)
+ {
+ error(location, "", "[",
+ "array indexes for fragment outputs must be constant integral expressions");
+ recover();
+ }
+ else if (mShaderSpec == SH_WEBGL2_SPEC && baseExpression->getQualifier() == EvqFragData)
+ {
+ error(location, "", "[", "array index for gl_FragData must be constant zero");
+ recover();
+ }
+ }
+
+ if (indexConstantUnion)
{
+ // If the index is not qualified as constant, the behavior in the spec is undefined. This
+ // applies even if ANGLE has been able to constant fold it (ANGLE may constant fold
+ // expressions that are not constant expressions). The most compatible way to handle this
+ // case is to report a warning instead of an error and force the index to be in the
+ // correct range.
+ bool outOfRangeIndexIsError = indexExpression->getQualifier() == EvqConst;
int index = indexConstantUnion->getIConst(0);
if (index < 0)
{
std::stringstream infoStream;
infoStream << index;
std::string info = infoStream.str();
- error(location, "negative index", info.c_str());
- recover();
+ outOfRangeError(outOfRangeIndexIsError, location, "negative index", info.c_str());
index = 0;
}
- if (baseExpression->getType().getQualifier() == EvqConst)
+ TIntermConstantUnion *baseConstantUnion = baseExpression->getAsConstantUnion();
+ if (baseConstantUnion)
{
if (baseExpression->isArray())
{
- // constant folding for arrays
- indexedExpression = addConstArrayNode(index, baseExpression, location);
+ // constant folding for array indexing
+ indexedExpression =
+ addConstArrayNode(index, baseConstantUnion, location, outOfRangeIndexIsError);
}
else if (baseExpression->isVector())
{
- // constant folding for vectors
+ // constant folding for vector indexing
TVectorFields fields;
fields.num = 1;
- fields.offsets[0] = index; // need to do it this way because v.xy sends fields integer array
- indexedExpression = addConstVectorNode(fields, baseExpression, location);
+ fields.offsets[0] =
+ index; // need to do it this way because v.xy sends fields integer array
+ indexedExpression =
+ addConstVectorNode(fields, baseConstantUnion, location, outOfRangeIndexIsError);
}
else if (baseExpression->isMatrix())
{
- // constant folding for matrices
- indexedExpression = addConstMatrixNode(index, baseExpression, location);
+ // constant folding for matrix indexing
+ indexedExpression =
+ addConstMatrixNode(index, baseConstantUnion, location, outOfRangeIndexIsError);
}
}
else
{
+ int safeIndex = -1;
+
if (baseExpression->isArray())
{
- if (index >= baseExpression->getType().getArraySize())
+ if (baseExpression->getQualifier() == EvqFragData && index > 0)
+ {
+ if (mShaderSpec == SH_WEBGL2_SPEC)
+ {
+ // Error has been already generated if index is not const.
+ if (indexExpression->getQualifier() == EvqConst)
+ {
+ error(location, "", "[",
+ "array index for gl_FragData must be constant zero");
+ recover();
+ }
+ safeIndex = 0;
+ }
+ else if (!isExtensionEnabled("GL_EXT_draw_buffers"))
+ {
+ outOfRangeError(outOfRangeIndexIsError, location, "", "[",
+ "array index for gl_FragData must be zero when "
+ "GL_EXT_draw_buffers is disabled");
+ safeIndex = 0;
+ }
+ }
+ // Only do generic out-of-range check if similar error hasn't already been reported.
+ if (safeIndex < 0 && index >= baseExpression->getType().getArraySize())
{
std::stringstream extraInfoStream;
extraInfoStream << "array index out of range '" << index << "'";
std::string extraInfo = extraInfoStream.str();
- error(location, "", "[", extraInfo.c_str());
- recover();
- index = baseExpression->getType().getArraySize() - 1;
- }
- else if (baseExpression->getQualifier() == EvqFragData && index > 0 && !isExtensionEnabled("GL_EXT_draw_buffers"))
- {
- error(location, "", "[", "array indexes for gl_FragData must be zero when GL_EXT_draw_buffers is disabled");
- recover();
- index = 0;
+ outOfRangeError(outOfRangeIndexIsError, location, "", "[", extraInfo.c_str());
+ safeIndex = baseExpression->getType().getArraySize() - 1;
}
}
- else if ((baseExpression->isVector() || baseExpression->isMatrix()) && baseExpression->getType().getNominalSize() <= index)
+ else if ((baseExpression->isVector() || baseExpression->isMatrix()) &&
+ baseExpression->getType().getNominalSize() <= index)
{
std::stringstream extraInfoStream;
extraInfoStream << "field selection out of range '" << index << "'";
std::string extraInfo = extraInfoStream.str();
- error(location, "", "[", extraInfo.c_str());
- recover();
- index = baseExpression->getType().getNominalSize() - 1;
+ outOfRangeError(outOfRangeIndexIsError, location, "", "[", extraInfo.c_str());
+ safeIndex = baseExpression->getType().getNominalSize() - 1;
+ }
+
+ // Data of constant unions can't be changed, because it may be shared with other
+ // constant unions or even builtins, like gl_MaxDrawBuffers. Instead use a new
+ // sanitized object.
+ if (safeIndex != -1)
+ {
+ TConstantUnion *safeConstantUnion = new TConstantUnion();
+ safeConstantUnion->setIConst(safeIndex);
+ indexConstantUnion->replaceConstantUnion(safeConstantUnion);
}
- indexConstantUnion->getUnionArrayPointer()->setIConst(index);
- indexedExpression = intermediate.addIndex(EOpIndexDirect, baseExpression, indexExpression, location);
+ indexedExpression =
+ intermediate.addIndex(EOpIndexDirect, baseExpression, indexExpression, location);
}
}
else
{
- if (baseExpression->isInterfaceBlock())
- {
- error(location, "", "[", "array indexes for interface blocks arrays must be constant integral expressions");
- recover();
- }
- else if (baseExpression->getQualifier() == EvqFragmentOut)
- {
- error(location, "", "[", "array indexes for fragment outputs must be constant integral expressions");
- recover();
- }
-
- indexedExpression = intermediate.addIndex(EOpIndexIndirect, baseExpression, indexExpression, location);
+ indexedExpression =
+ intermediate.addIndex(EOpIndexIndirect, baseExpression, indexExpression, location);
}
if (indexedExpression == 0)
{
- ConstantUnion *unionArray = new ConstantUnion[1];
+ TConstantUnion *unionArray = new TConstantUnion[1];
unionArray->setFConst(0.0f);
- indexedExpression = intermediate.addConstantUnion(unionArray, TType(EbtFloat, EbpHigh, EvqConst), location);
+ indexedExpression =
+ intermediate.addConstantUnion(unionArray, TType(EbtFloat, EbpHigh, EvqConst), location);
}
else if (baseExpression->isArray())
{
- const TType &baseType = baseExpression->getType();
- if (baseType.getStruct())
- {
- TType copyOfType(baseType.getStruct());
- indexedExpression->setType(copyOfType);
- }
- else if (baseType.isInterfaceBlock())
- {
- TType copyOfType(baseType.getInterfaceBlock(), baseType.getQualifier(), baseType.getLayoutQualifier(), 0);
- indexedExpression->setType(copyOfType);
- }
- else
- {
- indexedExpression->setType(TType(baseExpression->getBasicType(), baseExpression->getPrecision(), EvqTemporary, baseExpression->getNominalSize(), baseExpression->getSecondarySize()));
- }
-
- if (baseExpression->getType().getQualifier() == EvqConst)
- {
- indexedExpression->getTypePointer()->setQualifier(EvqConst);
- }
+ TType indexedType = baseExpression->getType();
+ indexedType.clearArrayness();
+ indexedExpression->setType(indexedType);
}
else if (baseExpression->isMatrix())
{
- TQualifier qualifier = baseExpression->getType().getQualifier() == EvqConst ? EvqConst : EvqTemporary;
- indexedExpression->setType(TType(baseExpression->getBasicType(), baseExpression->getPrecision(), qualifier, baseExpression->getRows()));
+ indexedExpression->setType(TType(baseExpression->getBasicType(),
+ baseExpression->getPrecision(), EvqTemporary,
+ static_cast<unsigned char>(baseExpression->getRows())));
}
else if (baseExpression->isVector())
{
- TQualifier qualifier = baseExpression->getType().getQualifier() == EvqConst ? EvqConst : EvqTemporary;
- indexedExpression->setType(TType(baseExpression->getBasicType(), baseExpression->getPrecision(), qualifier));
+ indexedExpression->setType(
+ TType(baseExpression->getBasicType(), baseExpression->getPrecision(), EvqTemporary));
}
else
{
indexedExpression->setType(baseExpression->getType());
}
+ if (baseExpression->getType().getQualifier() == EvqConst &&
+ indexExpression->getType().getQualifier() == EvqConst)
+ {
+ indexedExpression->getTypePointer()->setQualifier(EvqConst);
+ }
+ else
+ {
+ indexedExpression->getTypePointer()->setQualifier(EvqTemporary);
+ }
+
return indexedExpression;
}
-TIntermTyped* TParseContext::addFieldSelectionExpression(TIntermTyped *baseExpression, const TSourceLoc& dotLocation, const TString &fieldString, const TSourceLoc& fieldLocation)
+TIntermTyped *TParseContext::addFieldSelectionExpression(TIntermTyped *baseExpression,
+ const TSourceLoc &dotLocation,
+ const TString &fieldString,
+ const TSourceLoc &fieldLocation)
{
TIntermTyped *indexedExpression = NULL;
@@ -2217,70 +2978,43 @@ TIntermTyped* TParseContext::addFieldSelectionExpression(TIntermTyped *baseExpre
if (baseExpression->isVector())
{
TVectorFields fields;
- if (!parseVectorFields(fieldString, baseExpression->getNominalSize(), fields, fieldLocation))
+ if (!parseVectorFields(fieldString, baseExpression->getNominalSize(), fields,
+ fieldLocation))
{
- fields.num = 1;
+ fields.num = 1;
fields.offsets[0] = 0;
recover();
}
- if (baseExpression->getType().getQualifier() == EvqConst)
+ if (baseExpression->getAsConstantUnion())
{
// constant folding for vector fields
- indexedExpression = addConstVectorNode(fields, baseExpression, fieldLocation);
- if (indexedExpression == 0)
- {
- recover();
- indexedExpression = baseExpression;
- }
- else
- {
- indexedExpression->setType(TType(baseExpression->getBasicType(), baseExpression->getPrecision(), EvqConst, (int) (fieldString).size()));
- }
+ indexedExpression = addConstVectorNode(fields, baseExpression->getAsConstantUnion(),
+ fieldLocation, true);
}
else
{
- TString vectorString = fieldString;
- TIntermTyped* index = intermediate.addSwizzle(fields, fieldLocation);
- indexedExpression = intermediate.addIndex(EOpVectorSwizzle, baseExpression, index, dotLocation);
- indexedExpression->setType(TType(baseExpression->getBasicType(), baseExpression->getPrecision(), EvqTemporary, (int) vectorString.size()));
- }
- }
- else if (baseExpression->isMatrix())
- {
- TMatrixFields fields;
- if (!parseMatrixFields(fieldString, baseExpression->getCols(), baseExpression->getRows(), fields, fieldLocation))
- {
- fields.wholeRow = false;
- fields.wholeCol = false;
- fields.row = 0;
- fields.col = 0;
- recover();
+ TIntermTyped *index = intermediate.addSwizzle(fields, fieldLocation);
+ indexedExpression =
+ intermediate.addIndex(EOpVectorSwizzle, baseExpression, index, dotLocation);
}
-
- if (fields.wholeRow || fields.wholeCol)
+ if (indexedExpression == nullptr)
{
- error(dotLocation, " non-scalar fields not implemented yet", ".");
recover();
- ConstantUnion *unionArray = new ConstantUnion[1];
- unionArray->setIConst(0);
- TIntermTyped* index = intermediate.addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), fieldLocation);
- indexedExpression = intermediate.addIndex(EOpIndexDirect, baseExpression, index, dotLocation);
- indexedExpression->setType(TType(baseExpression->getBasicType(), baseExpression->getPrecision(),EvqTemporary, baseExpression->getCols(), baseExpression->getRows()));
+ indexedExpression = baseExpression;
}
else
{
- ConstantUnion *unionArray = new ConstantUnion[1];
- unionArray->setIConst(fields.col * baseExpression->getRows() + fields.row);
- TIntermTyped* index = intermediate.addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), fieldLocation);
- indexedExpression = intermediate.addIndex(EOpIndexDirect, baseExpression, index, dotLocation);
- indexedExpression->setType(TType(baseExpression->getBasicType(), baseExpression->getPrecision()));
+ // Note that the qualifier set here will be corrected later.
+ indexedExpression->setType(TType(baseExpression->getBasicType(),
+ baseExpression->getPrecision(), EvqTemporary,
+ (unsigned char)(fieldString).size()));
}
}
else if (baseExpression->getBasicType() == EbtStruct)
{
- bool fieldFound = false;
- const TFieldList& fields = baseExpression->getType().getStruct()->fields();
+ bool fieldFound = false;
+ const TFieldList &fields = baseExpression->getType().getStruct()->fields();
if (fields.empty())
{
error(dotLocation, "structure has no fields", "Internal Error");
@@ -2300,7 +3034,7 @@ TIntermTyped* TParseContext::addFieldSelectionExpression(TIntermTyped *baseExpre
}
if (fieldFound)
{
- if (baseExpression->getType().getQualifier() == EvqConst)
+ if (baseExpression->getAsConstantUnion())
{
indexedExpression = addConstStruct(fieldString, baseExpression, dotLocation);
if (indexedExpression == 0)
@@ -2311,17 +3045,16 @@ TIntermTyped* TParseContext::addFieldSelectionExpression(TIntermTyped *baseExpre
else
{
indexedExpression->setType(*fields[i]->type());
- // change the qualifier of the return type, not of the structure field
- // as the structure definition is shared between various structures.
- indexedExpression->getTypePointer()->setQualifier(EvqConst);
}
}
else
{
- ConstantUnion *unionArray = new ConstantUnion[1];
+ TConstantUnion *unionArray = new TConstantUnion[1];
unionArray->setIConst(i);
- TIntermTyped* index = intermediate.addConstantUnion(unionArray, *fields[i]->type(), fieldLocation);
- indexedExpression = intermediate.addIndex(EOpIndexDirectStruct, baseExpression, index, dotLocation);
+ TIntermTyped *index = intermediate.addConstantUnion(
+ unionArray, *fields[i]->type(), fieldLocation);
+ indexedExpression = intermediate.addIndex(EOpIndexDirectStruct, baseExpression,
+ index, dotLocation);
indexedExpression->setType(*fields[i]->type());
}
}
@@ -2335,8 +3068,8 @@ TIntermTyped* TParseContext::addFieldSelectionExpression(TIntermTyped *baseExpre
}
else if (baseExpression->isInterfaceBlock())
{
- bool fieldFound = false;
- const TFieldList& fields = baseExpression->getType().getInterfaceBlock()->fields();
+ bool fieldFound = false;
+ const TFieldList &fields = baseExpression->getType().getInterfaceBlock()->fields();
if (fields.empty())
{
error(dotLocation, "interface block has no fields", "Internal Error");
@@ -2356,10 +3089,12 @@ TIntermTyped* TParseContext::addFieldSelectionExpression(TIntermTyped *baseExpre
}
if (fieldFound)
{
- ConstantUnion *unionArray = new ConstantUnion[1];
+ TConstantUnion *unionArray = new TConstantUnion[1];
unionArray->setIConst(i);
- TIntermTyped* index = intermediate.addConstantUnion(unionArray, *fields[i]->type(), fieldLocation);
- indexedExpression = intermediate.addIndex(EOpIndexDirectInterfaceBlock, baseExpression, index, dotLocation);
+ TIntermTyped *index =
+ intermediate.addConstantUnion(unionArray, *fields[i]->type(), fieldLocation);
+ indexedExpression = intermediate.addIndex(EOpIndexDirectInterfaceBlock,
+ baseExpression, index, dotLocation);
indexedExpression->setType(*fields[i]->type());
}
else
@@ -2372,28 +3107,42 @@ TIntermTyped* TParseContext::addFieldSelectionExpression(TIntermTyped *baseExpre
}
else
{
- if (shaderVersion < 300)
+ if (mShaderVersion < 300)
{
- error(dotLocation, " field selection requires structure, vector, or matrix on left hand side", fieldString.c_str());
+ error(dotLocation, " field selection requires structure or vector on left hand side",
+ fieldString.c_str());
}
else
{
- error(dotLocation, " field selection requires structure, vector, matrix, or interface block on left hand side", fieldString.c_str());
+ error(dotLocation,
+ " field selection requires structure, vector, or interface block on left hand "
+ "side",
+ fieldString.c_str());
}
recover();
indexedExpression = baseExpression;
}
+ if (baseExpression->getQualifier() == EvqConst)
+ {
+ indexedExpression->getTypePointer()->setQualifier(EvqConst);
+ }
+ else
+ {
+ indexedExpression->getTypePointer()->setQualifier(EvqTemporary);
+ }
+
return indexedExpression;
}
-TLayoutQualifier TParseContext::parseLayoutQualifier(const TString &qualifierType, const TSourceLoc& qualifierTypeLine)
+TLayoutQualifier TParseContext::parseLayoutQualifier(const TString &qualifierType,
+ const TSourceLoc &qualifierTypeLine)
{
TLayoutQualifier qualifier;
- qualifier.location = -1;
+ qualifier.location = -1;
qualifier.matrixPacking = EmpUnspecified;
- qualifier.blockStorage = EbsUnspecified;
+ qualifier.blockStorage = EbsUnspecified;
if (qualifierType == "shared")
{
@@ -2417,7 +3166,8 @@ TLayoutQualifier TParseContext::parseLayoutQualifier(const TString &qualifierTyp
}
else if (qualifierType == "location")
{
- error(qualifierTypeLine, "invalid layout qualifier", qualifierType.c_str(), "location requires an argument");
+ error(qualifierTypeLine, "invalid layout qualifier", qualifierType.c_str(),
+ "location requires an argument");
recover();
}
else
@@ -2429,17 +3179,22 @@ TLayoutQualifier TParseContext::parseLayoutQualifier(const TString &qualifierTyp
return qualifier;
}
-TLayoutQualifier TParseContext::parseLayoutQualifier(const TString &qualifierType, const TSourceLoc& qualifierTypeLine, const TString &intValueString, int intValue, const TSourceLoc& intValueLine)
+TLayoutQualifier TParseContext::parseLayoutQualifier(const TString &qualifierType,
+ const TSourceLoc &qualifierTypeLine,
+ const TString &intValueString,
+ int intValue,
+ const TSourceLoc &intValueLine)
{
TLayoutQualifier qualifier;
- qualifier.location = -1;
+ qualifier.location = -1;
qualifier.matrixPacking = EmpUnspecified;
- qualifier.blockStorage = EbsUnspecified;
+ qualifier.blockStorage = EbsUnspecified;
if (qualifierType != "location")
{
- error(qualifierTypeLine, "invalid layout qualifier", qualifierType.c_str(), "only location may have arguments");
+ error(qualifierTypeLine, "invalid layout qualifier", qualifierType.c_str(),
+ "only location may have arguments");
recover();
}
else
@@ -2447,7 +3202,8 @@ TLayoutQualifier TParseContext::parseLayoutQualifier(const TString &qualifierTyp
// must check that location is non-negative
if (intValue < 0)
{
- error(intValueLine, "out of range:", intValueString.c_str(), "location must be non-negative");
+ error(intValueLine, "out of range:", intValueString.c_str(),
+ "location must be non-negative");
recover();
}
else
@@ -2459,7 +3215,8 @@ TLayoutQualifier TParseContext::parseLayoutQualifier(const TString &qualifierTyp
return qualifier;
}
-TLayoutQualifier TParseContext::joinLayoutQualifiers(TLayoutQualifier leftQualifier, TLayoutQualifier rightQualifier)
+TLayoutQualifier TParseContext::joinLayoutQualifiers(TLayoutQualifier leftQualifier,
+ TLayoutQualifier rightQualifier)
{
TLayoutQualifier joinedQualifier = leftQualifier;
@@ -2479,41 +3236,54 @@ TLayoutQualifier TParseContext::joinLayoutQualifiers(TLayoutQualifier leftQualif
return joinedQualifier;
}
-TPublicType TParseContext::joinInterpolationQualifiers(const TSourceLoc &interpolationLoc, TQualifier interpolationQualifier,
- const TSourceLoc &storageLoc, TQualifier storageQualifier)
+TPublicType TParseContext::joinInterpolationQualifiers(const TSourceLoc &interpolationLoc,
+ TQualifier interpolationQualifier,
+ const TSourceLoc &storageLoc,
+ TQualifier storageQualifier)
{
TQualifier mergedQualifier = EvqSmoothIn;
- if (storageQualifier == EvqFragmentIn) {
+ if (storageQualifier == EvqFragmentIn)
+ {
if (interpolationQualifier == EvqSmooth)
mergedQualifier = EvqSmoothIn;
else if (interpolationQualifier == EvqFlat)
mergedQualifier = EvqFlatIn;
- else UNREACHABLE();
+ else
+ UNREACHABLE();
}
- else if (storageQualifier == EvqCentroidIn) {
+ else if (storageQualifier == EvqCentroidIn)
+ {
if (interpolationQualifier == EvqSmooth)
mergedQualifier = EvqCentroidIn;
else if (interpolationQualifier == EvqFlat)
mergedQualifier = EvqFlatIn;
- else UNREACHABLE();
+ else
+ UNREACHABLE();
}
- else if (storageQualifier == EvqVertexOut) {
+ else if (storageQualifier == EvqVertexOut)
+ {
if (interpolationQualifier == EvqSmooth)
mergedQualifier = EvqSmoothOut;
else if (interpolationQualifier == EvqFlat)
mergedQualifier = EvqFlatOut;
- else UNREACHABLE();
+ else
+ UNREACHABLE();
}
- else if (storageQualifier == EvqCentroidOut) {
+ else if (storageQualifier == EvqCentroidOut)
+ {
if (interpolationQualifier == EvqSmooth)
mergedQualifier = EvqCentroidOut;
else if (interpolationQualifier == EvqFlat)
mergedQualifier = EvqFlatOut;
- else UNREACHABLE();
+ else
+ UNREACHABLE();
}
- else {
- error(interpolationLoc, "interpolation qualifier requires a fragment 'in' or vertex 'out' storage qualifier", getInterpolationString(interpolationQualifier));
+ else
+ {
+ error(interpolationLoc,
+ "interpolation qualifier requires a fragment 'in' or vertex 'out' storage qualifier",
+ getInterpolationString(interpolationQualifier));
recover();
mergedQualifier = storageQualifier;
@@ -2524,17 +3294,20 @@ TPublicType TParseContext::joinInterpolationQualifiers(const TSourceLoc &interpo
return type;
}
-TFieldList *TParseContext::addStructDeclaratorList(const TPublicType& typeSpecifier, TFieldList *fieldList)
+TFieldList *TParseContext::addStructDeclaratorList(const TPublicType &typeSpecifier,
+ TFieldList *fieldList)
{
- if (voidErrorCheck(typeSpecifier.line, (*fieldList)[0]->name(), typeSpecifier)) {
+ if (voidErrorCheck(typeSpecifier.line, (*fieldList)[0]->name(), typeSpecifier.type))
+ {
recover();
}
- for (unsigned int i = 0; i < fieldList->size(); ++i) {
+ for (unsigned int i = 0; i < fieldList->size(); ++i)
+ {
//
// Careful not to replace already known aspects of type, like array-ness
//
- TType* type = (*fieldList)[i]->type();
+ TType *type = (*fieldList)[i]->type();
type->setBasicType(typeSpecifier.type);
type->setPrimarySize(typeSpecifier.primarySize);
type->setSecondarySize(typeSpecifier.secondarySize);
@@ -2543,17 +3316,20 @@ TFieldList *TParseContext::addStructDeclaratorList(const TPublicType& typeSpecif
type->setLayoutQualifier(typeSpecifier.layoutQualifier);
// don't allow arrays of arrays
- if (type->isArray()) {
+ if (type->isArray())
+ {
if (arrayTypeErrorCheck(typeSpecifier.line, typeSpecifier))
recover();
}
if (typeSpecifier.array)
type->setArraySize(typeSpecifier.arraySize);
- if (typeSpecifier.userDef) {
+ if (typeSpecifier.userDef)
+ {
type->setStruct(typeSpecifier.userDef->getStruct());
}
- if (structNestingErrorCheck(typeSpecifier.line, *(*fieldList)[i])) {
+ if (structNestingErrorCheck(typeSpecifier.line, *(*fieldList)[i]))
+ {
recover();
}
}
@@ -2561,10 +3337,13 @@ TFieldList *TParseContext::addStructDeclaratorList(const TPublicType& typeSpecif
return fieldList;
}
-TPublicType TParseContext::addStructure(const TSourceLoc& structLine, const TSourceLoc& nameLine, const TString *structName, TFieldList* fieldList)
+TPublicType TParseContext::addStructure(const TSourceLoc &structLine,
+ const TSourceLoc &nameLine,
+ const TString *structName,
+ TFieldList *fieldList)
{
- TStructure* structure = new TStructure(structName, fieldList);
- TType* structureType = new TType(structure);
+ TStructure *structure = new TStructure(structName, fieldList);
+ TType *structureType = new TType(structure);
// Store a bool in the struct if we're at global scope, to allow us to
// skip the local struct scoping workaround in HLSL.
@@ -2577,8 +3356,9 @@ TPublicType TParseContext::addStructure(const TSourceLoc& structLine, const TSou
{
recover();
}
- TVariable* userTypeDef = new TVariable(structName, *structureType, true);
- if (!symbolTable.declare(userTypeDef)) {
+ TVariable *userTypeDef = new TVariable(structName, *structureType, true);
+ if (!symbolTable.declare(userTypeDef))
+ {
error(nameLine, "redefinition", structName->c_str(), "struct");
recover();
}
@@ -2587,37 +3367,40 @@ TPublicType TParseContext::addStructure(const TSourceLoc& structLine, const TSou
// ensure we do not specify any storage qualifiers on the struct members
for (unsigned int typeListIndex = 0; typeListIndex < fieldList->size(); typeListIndex++)
{
- const TField &field = *(*fieldList)[typeListIndex];
+ const TField &field = *(*fieldList)[typeListIndex];
const TQualifier qualifier = field.type()->getQualifier();
switch (qualifier)
{
- case EvqGlobal:
- case EvqTemporary:
- break;
- default:
- error(field.line(), "invalid qualifier on struct member", getQualifierString(qualifier));
- recover();
- break;
+ case EvqGlobal:
+ case EvqTemporary:
+ break;
+ default:
+ error(field.line(), "invalid qualifier on struct member",
+ getQualifierString(qualifier));
+ recover();
+ break;
}
}
TPublicType publicType;
publicType.setBasic(EbtStruct, EvqTemporary, structLine);
publicType.userDef = structureType;
+ publicType.isStructSpecifier = true;
exitStructDeclaration();
return publicType;
}
-TIntermSwitch *TParseContext::addSwitch(TIntermTyped *init, TIntermAggregate *statementList, const TSourceLoc &loc)
+TIntermSwitch *TParseContext::addSwitch(TIntermTyped *init,
+ TIntermAggregate *statementList,
+ const TSourceLoc &loc)
{
TBasicType switchType = init->getBasicType();
- if ((switchType != EbtInt && switchType != EbtUInt) ||
- init->isMatrix() ||
- init->isArray() ||
+ if ((switchType != EbtInt && switchType != EbtUInt) || init->isMatrix() || init->isArray() ||
init->isVector())
{
- error(init->getLine(), "init-expression in a switch statement must be a scalar integer", "switch");
+ error(init->getLine(), "init-expression in a switch statement must be a scalar integer",
+ "switch");
recover();
return nullptr;
}
@@ -2656,15 +3439,16 @@ TIntermCase *TParseContext::addCase(TIntermTyped *condition, const TSourceLoc &l
return nullptr;
}
if ((condition->getBasicType() != EbtInt && condition->getBasicType() != EbtUInt) ||
- condition->isMatrix() ||
- condition->isArray() ||
- condition->isVector())
+ condition->isMatrix() || condition->isArray() || condition->isVector())
{
error(condition->getLine(), "case label must be a scalar integer", "case");
recover();
}
TIntermConstantUnion *conditionConst = condition->getAsConstantUnion();
- if (conditionConst == nullptr)
+ // TODO(oetuaho@nvidia.com): Get rid of the conditionConst == nullptr check once all constant
+ // expressions can be folded. Right now we don't allow constant expressions that ANGLE can't
+ // fold in case labels.
+ if (condition->getQualifier() != EvqConst || conditionConst == nullptr)
{
error(condition->getLine(), "case label must be constant", "case");
recover();
@@ -2697,8 +3481,10 @@ TIntermCase *TParseContext::addDefault(const TSourceLoc &loc)
return node;
}
-TIntermTyped *TParseContext::createUnaryMath(TOperator op, TIntermTyped *child, const TSourceLoc &loc,
- const TType *funcReturnType)
+TIntermTyped *TParseContext::createUnaryMath(TOperator op,
+ TIntermTyped *child,
+ const TSourceLoc &loc,
+ const TType *funcReturnType)
{
if (child == nullptr)
{
@@ -2707,38 +3493,34 @@ TIntermTyped *TParseContext::createUnaryMath(TOperator op, TIntermTyped *child,
switch (op)
{
- case EOpLogicalNot:
- if (child->getBasicType() != EbtBool ||
- child->isMatrix() ||
- child->isArray() ||
- child->isVector())
- {
- return nullptr;
- }
- break;
- case EOpBitwiseNot:
- if ((child->getBasicType() != EbtInt && child->getBasicType() != EbtUInt) ||
- child->isMatrix() ||
- child->isArray())
- {
- return nullptr;
- }
- break;
- case EOpPostIncrement:
- case EOpPreIncrement:
- case EOpPostDecrement:
- case EOpPreDecrement:
- case EOpNegative:
- case EOpPositive:
- if (child->getBasicType() == EbtStruct ||
- child->getBasicType() == EbtBool ||
- child->isArray())
- {
- return nullptr;
- }
- // Operators for built-ins are already type checked against their prototype.
- default:
- break;
+ case EOpLogicalNot:
+ if (child->getBasicType() != EbtBool || child->isMatrix() || child->isArray() ||
+ child->isVector())
+ {
+ return nullptr;
+ }
+ break;
+ case EOpBitwiseNot:
+ if ((child->getBasicType() != EbtInt && child->getBasicType() != EbtUInt) ||
+ child->isMatrix() || child->isArray())
+ {
+ return nullptr;
+ }
+ break;
+ case EOpPostIncrement:
+ case EOpPreIncrement:
+ case EOpPostDecrement:
+ case EOpPreDecrement:
+ case EOpNegative:
+ case EOpPositive:
+ if (child->getBasicType() == EbtStruct || child->getBasicType() == EbtBool ||
+ child->isArray())
+ {
+ return nullptr;
+ }
+ // Operators for built-ins are already type checked against their prototype.
+ default:
+ break;
}
return intermediate.addUnaryMath(op, child, loc, funcReturnType);
@@ -2756,19 +3538,23 @@ TIntermTyped *TParseContext::addUnaryMath(TOperator op, TIntermTyped *child, con
return node;
}
-TIntermTyped *TParseContext::addUnaryMathLValue(TOperator op, TIntermTyped *child, const TSourceLoc &loc)
+TIntermTyped *TParseContext::addUnaryMathLValue(TOperator op,
+ TIntermTyped *child,
+ const TSourceLoc &loc)
{
if (lValueErrorCheck(loc, GetOperatorString(op), child))
recover();
return addUnaryMath(op, child, loc);
}
-bool TParseContext::binaryOpCommonCheck(TOperator op, TIntermTyped *left, TIntermTyped *right,
- const TSourceLoc &loc)
+bool TParseContext::binaryOpCommonCheck(TOperator op,
+ TIntermTyped *left,
+ TIntermTyped *right,
+ const TSourceLoc &loc)
{
if (left->isArray() || right->isArray())
{
- if (shaderVersion < 300)
+ if (mShaderVersion < 300)
{
error(loc, "Invalid operation for arrays", GetOperatorString(op));
return false;
@@ -2782,15 +3568,16 @@ bool TParseContext::binaryOpCommonCheck(TOperator op, TIntermTyped *left, TInter
switch (op)
{
- case EOpEqual:
- case EOpNotEqual:
- case EOpAssign:
- case EOpInitialize:
- break;
- default:
- error(loc, "Invalid operation for arrays", GetOperatorString(op));
- return false;
+ case EOpEqual:
+ case EOpNotEqual:
+ case EOpAssign:
+ case EOpInitialize:
+ break;
+ default:
+ error(loc, "Invalid operation for arrays", GetOperatorString(op));
+ return false;
}
+ // At this point, size of implicitly sized arrays should be resolved.
if (left->getArraySize() != right->getArraySize())
{
error(loc, "array size mismatch", GetOperatorString(op));
@@ -2802,33 +3589,33 @@ bool TParseContext::binaryOpCommonCheck(TOperator op, TIntermTyped *left, TInter
bool isBitShift = false;
switch (op)
{
- case EOpBitShiftLeft:
- case EOpBitShiftRight:
- case EOpBitShiftLeftAssign:
- case EOpBitShiftRightAssign:
- // Unsigned can be bit-shifted by signed and vice versa, but we need to
- // check that the basic type is an integer type.
- isBitShift = true;
- if (!IsInteger(left->getBasicType()) || !IsInteger(right->getBasicType()))
- {
- return false;
- }
- break;
- case EOpBitwiseAnd:
- case EOpBitwiseXor:
- case EOpBitwiseOr:
- case EOpBitwiseAndAssign:
- case EOpBitwiseXorAssign:
- case EOpBitwiseOrAssign:
- // It is enough to check the type of only one operand, since later it
- // is checked that the operand types match.
- if (!IsInteger(left->getBasicType()))
- {
- return false;
- }
- break;
- default:
- break;
+ case EOpBitShiftLeft:
+ case EOpBitShiftRight:
+ case EOpBitShiftLeftAssign:
+ case EOpBitShiftRightAssign:
+ // Unsigned can be bit-shifted by signed and vice versa, but we need to
+ // check that the basic type is an integer type.
+ isBitShift = true;
+ if (!IsInteger(left->getBasicType()) || !IsInteger(right->getBasicType()))
+ {
+ return false;
+ }
+ break;
+ case EOpBitwiseAnd:
+ case EOpBitwiseXor:
+ case EOpBitwiseOr:
+ case EOpBitwiseAndAssign:
+ case EOpBitwiseXorAssign:
+ case EOpBitwiseOrAssign:
+ // It is enough to check the type of only one operand, since later it
+ // is checked that the operand types match.
+ if (!IsInteger(left->getBasicType()))
+ {
+ return false;
+ }
+ break;
+ default:
+ break;
}
// GLSL ES 1.00 and 3.00 do not support implicit type casting.
@@ -2840,132 +3627,144 @@ bool TParseContext::binaryOpCommonCheck(TOperator op, TIntermTyped *left, TInter
// Check that type sizes match exactly on ops that require that.
// Also check restrictions for structs that contain arrays or samplers.
- switch(op)
+ switch (op)
{
- case EOpAssign:
- case EOpInitialize:
- case EOpEqual:
- case EOpNotEqual:
- // ESSL 1.00 sections 5.7, 5.8, 5.9
- if (shaderVersion < 300 && left->getType().isStructureContainingArrays())
- {
- error(loc, "undefined operation for structs containing arrays", GetOperatorString(op));
- return false;
- }
- // Samplers as l-values are disallowed also in ESSL 3.00, see section 4.1.7,
- // we interpret the spec so that this extends to structs containing samplers,
- // similarly to ESSL 1.00 spec.
- if ((shaderVersion < 300 || op == EOpAssign || op == EOpInitialize) &&
- left->getType().isStructureContainingSamplers())
- {
- error(loc, "undefined operation for structs containing samplers", GetOperatorString(op));
- return false;
- }
- case EOpLessThan:
- case EOpGreaterThan:
- case EOpLessThanEqual:
- case EOpGreaterThanEqual:
- if ((left->getNominalSize() != right->getNominalSize()) ||
- (left->getSecondarySize() != right->getSecondarySize()))
- {
- return false;
- }
- default:
- break;
+ case EOpAssign:
+ case EOpInitialize:
+ case EOpEqual:
+ case EOpNotEqual:
+ // ESSL 1.00 sections 5.7, 5.8, 5.9
+ if (mShaderVersion < 300 && left->getType().isStructureContainingArrays())
+ {
+ error(loc, "undefined operation for structs containing arrays",
+ GetOperatorString(op));
+ return false;
+ }
+ // Samplers as l-values are disallowed also in ESSL 3.00, see section 4.1.7,
+ // we interpret the spec so that this extends to structs containing samplers,
+ // similarly to ESSL 1.00 spec.
+ if ((mShaderVersion < 300 || op == EOpAssign || op == EOpInitialize) &&
+ left->getType().isStructureContainingSamplers())
+ {
+ error(loc, "undefined operation for structs containing samplers",
+ GetOperatorString(op));
+ return false;
+ }
+ case EOpLessThan:
+ case EOpGreaterThan:
+ case EOpLessThanEqual:
+ case EOpGreaterThanEqual:
+ if ((left->getNominalSize() != right->getNominalSize()) ||
+ (left->getSecondarySize() != right->getSecondarySize()))
+ {
+ return false;
+ }
+ default:
+ break;
}
return true;
}
-TIntermTyped *TParseContext::addBinaryMathInternal(TOperator op, TIntermTyped *left, TIntermTyped *right,
- const TSourceLoc &loc)
+TIntermTyped *TParseContext::addBinaryMathInternal(TOperator op,
+ TIntermTyped *left,
+ TIntermTyped *right,
+ const TSourceLoc &loc)
{
if (!binaryOpCommonCheck(op, left, right, loc))
return nullptr;
switch (op)
{
- case EOpEqual:
- case EOpNotEqual:
- break;
- case EOpLessThan:
- case EOpGreaterThan:
- case EOpLessThanEqual:
- case EOpGreaterThanEqual:
- ASSERT(!left->isArray() && !right->isArray());
- if (left->isMatrix() || left->isVector() ||
- left->getBasicType() == EbtStruct)
- {
- return nullptr;
- }
- break;
- case EOpLogicalOr:
- case EOpLogicalXor:
- case EOpLogicalAnd:
- ASSERT(!left->isArray() && !right->isArray());
- if (left->getBasicType() != EbtBool ||
- left->isMatrix() || left->isVector())
- {
- return nullptr;
- }
- break;
- case EOpAdd:
- case EOpSub:
- case EOpDiv:
- case EOpMul:
- ASSERT(!left->isArray() && !right->isArray());
- if (left->getBasicType() == EbtStruct || left->getBasicType() == EbtBool)
- {
- return nullptr;
- }
- break;
- case EOpIMod:
- ASSERT(!left->isArray() && !right->isArray());
- // Note that this is only for the % operator, not for mod()
- if (left->getBasicType() == EbtStruct || left->getBasicType() == EbtBool || left->getBasicType() == EbtFloat)
- {
- return nullptr;
- }
- break;
- // Note that for bitwise ops, type checking is done in promote() to
- // share code between ops and compound assignment
- default:
- break;
+ case EOpEqual:
+ case EOpNotEqual:
+ break;
+ case EOpLessThan:
+ case EOpGreaterThan:
+ case EOpLessThanEqual:
+ case EOpGreaterThanEqual:
+ ASSERT(!left->isArray() && !right->isArray());
+ if (left->isMatrix() || left->isVector() || left->getBasicType() == EbtStruct)
+ {
+ return nullptr;
+ }
+ break;
+ case EOpLogicalOr:
+ case EOpLogicalXor:
+ case EOpLogicalAnd:
+ ASSERT(!left->isArray() && !right->isArray());
+ if (left->getBasicType() != EbtBool || left->isMatrix() || left->isVector())
+ {
+ return nullptr;
+ }
+ break;
+ case EOpAdd:
+ case EOpSub:
+ case EOpDiv:
+ case EOpMul:
+ ASSERT(!left->isArray() && !right->isArray());
+ if (left->getBasicType() == EbtStruct || left->getBasicType() == EbtBool)
+ {
+ return nullptr;
+ }
+ break;
+ case EOpIMod:
+ ASSERT(!left->isArray() && !right->isArray());
+ // Note that this is only for the % operator, not for mod()
+ if (left->getBasicType() == EbtStruct || left->getBasicType() == EbtBool ||
+ left->getBasicType() == EbtFloat)
+ {
+ return nullptr;
+ }
+ break;
+ // Note that for bitwise ops, type checking is done in promote() to
+ // share code between ops and compound assignment
+ default:
+ break;
}
return intermediate.addBinaryMath(op, left, right, loc);
}
-TIntermTyped *TParseContext::addBinaryMath(TOperator op, TIntermTyped *left, TIntermTyped *right,
- const TSourceLoc &loc)
+TIntermTyped *TParseContext::addBinaryMath(TOperator op,
+ TIntermTyped *left,
+ TIntermTyped *right,
+ const TSourceLoc &loc)
{
TIntermTyped *node = addBinaryMathInternal(op, left, right, loc);
if (node == 0)
{
- binaryOpError(loc, GetOperatorString(op), left->getCompleteString(), right->getCompleteString());
+ binaryOpError(loc, GetOperatorString(op), left->getCompleteString(),
+ right->getCompleteString());
recover();
return left;
}
return node;
}
-TIntermTyped *TParseContext::addBinaryMathBooleanResult(TOperator op, TIntermTyped *left, TIntermTyped *right,
- const TSourceLoc &loc)
+TIntermTyped *TParseContext::addBinaryMathBooleanResult(TOperator op,
+ TIntermTyped *left,
+ TIntermTyped *right,
+ const TSourceLoc &loc)
{
TIntermTyped *node = addBinaryMathInternal(op, left, right, loc);
if (node == 0)
{
- binaryOpError(loc, GetOperatorString(op), left->getCompleteString(), right->getCompleteString());
+ binaryOpError(loc, GetOperatorString(op), left->getCompleteString(),
+ right->getCompleteString());
recover();
- ConstantUnion *unionArray = new ConstantUnion[1];
+ TConstantUnion *unionArray = new TConstantUnion[1];
unionArray->setBConst(false);
- return intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), loc);
+ return intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst),
+ loc);
}
return node;
}
-TIntermTyped *TParseContext::createAssign(TOperator op, TIntermTyped *left, TIntermTyped *right,
- const TSourceLoc &loc)
+TIntermTyped *TParseContext::createAssign(TOperator op,
+ TIntermTyped *left,
+ TIntermTyped *right,
+ const TSourceLoc &loc)
{
if (binaryOpCommonCheck(op, left, right, loc))
{
@@ -2974,8 +3773,10 @@ TIntermTyped *TParseContext::createAssign(TOperator op, TIntermTyped *left, TInt
return nullptr;
}
-TIntermTyped *TParseContext::addAssign(TOperator op, TIntermTyped *left, TIntermTyped *right,
- const TSourceLoc &loc)
+TIntermTyped *TParseContext::addAssign(TOperator op,
+ TIntermTyped *left,
+ TIntermTyped *right,
+ const TSourceLoc &loc)
{
TIntermTyped *node = createAssign(op, left, right, loc);
if (node == nullptr)
@@ -2987,48 +3788,57 @@ TIntermTyped *TParseContext::addAssign(TOperator op, TIntermTyped *left, TInterm
return node;
}
+TIntermTyped *TParseContext::addComma(TIntermTyped *left,
+ TIntermTyped *right,
+ const TSourceLoc &loc)
+{
+ return intermediate.addComma(left, right, loc, mShaderVersion);
+}
+
TIntermBranch *TParseContext::addBranch(TOperator op, const TSourceLoc &loc)
{
switch (op)
{
- case EOpContinue:
- if (mLoopNestingLevel <= 0)
- {
- error(loc, "continue statement only allowed in loops", "");
- recover();
- }
- break;
- case EOpBreak:
- if (mLoopNestingLevel <= 0 && mSwitchNestingLevel <= 0)
- {
- error(loc, "break statement only allowed in loops and switch statements", "");
- recover();
- }
- break;
- case EOpReturn:
- if (currentFunctionType->getBasicType() != EbtVoid)
- {
- error(loc, "non-void function must return a value", "return");
- recover();
- }
- break;
- default:
- // No checks for discard
- break;
+ case EOpContinue:
+ if (mLoopNestingLevel <= 0)
+ {
+ error(loc, "continue statement only allowed in loops", "");
+ recover();
+ }
+ break;
+ case EOpBreak:
+ if (mLoopNestingLevel <= 0 && mSwitchNestingLevel <= 0)
+ {
+ error(loc, "break statement only allowed in loops and switch statements", "");
+ recover();
+ }
+ break;
+ case EOpReturn:
+ if (mCurrentFunctionType->getBasicType() != EbtVoid)
+ {
+ error(loc, "non-void function must return a value", "return");
+ recover();
+ }
+ break;
+ default:
+ // No checks for discard
+ break;
}
return intermediate.addBranch(op, loc);
}
-TIntermBranch *TParseContext::addBranch(TOperator op, TIntermTyped *returnValue, const TSourceLoc &loc)
+TIntermBranch *TParseContext::addBranch(TOperator op,
+ TIntermTyped *returnValue,
+ const TSourceLoc &loc)
{
ASSERT(op == EOpReturn);
mFunctionReturnsValue = true;
- if (currentFunctionType->getBasicType() == EbtVoid)
+ if (mCurrentFunctionType->getBasicType() == EbtVoid)
{
error(loc, "void function cannot return a value", "return");
recover();
}
- else if (*currentFunctionType != returnValue->getType())
+ else if (*mCurrentFunctionType != returnValue->getType())
{
error(loc, "function return is not matching type:", "return");
recover();
@@ -3036,14 +3846,113 @@ TIntermBranch *TParseContext::addBranch(TOperator op, TIntermTyped *returnValue,
return intermediate.addBranch(op, returnValue, loc);
}
-TIntermTyped *TParseContext::addFunctionCallOrMethod(TFunction *fnCall, TIntermNode *node,
- const TSourceLoc &loc, bool *fatalError)
+void TParseContext::checkTextureOffsetConst(TIntermAggregate *functionCall)
{
- *fatalError = false;
- TOperator op = fnCall->getBuiltInOp();
+ ASSERT(!functionCall->isUserDefined());
+ const TString &name = functionCall->getName();
+ TIntermNode *offset = nullptr;
+ TIntermSequence *arguments = functionCall->getSequence();
+ if (name.compare(0, 16, "texelFetchOffset") == 0 ||
+ name.compare(0, 16, "textureLodOffset") == 0 ||
+ name.compare(0, 20, "textureProjLodOffset") == 0 ||
+ name.compare(0, 17, "textureGradOffset") == 0 ||
+ name.compare(0, 21, "textureProjGradOffset") == 0)
+ {
+ offset = arguments->back();
+ }
+ else if (name.compare(0, 13, "textureOffset") == 0 ||
+ name.compare(0, 17, "textureProjOffset") == 0)
+ {
+ // A bias parameter might follow the offset parameter.
+ ASSERT(arguments->size() >= 3);
+ offset = (*arguments)[2];
+ }
+ if (offset != nullptr)
+ {
+ TIntermConstantUnion *offsetConstantUnion = offset->getAsConstantUnion();
+ if (offset->getAsTyped()->getQualifier() != EvqConst || !offsetConstantUnion)
+ {
+ TString unmangledName = TFunction::unmangleName(name);
+ error(functionCall->getLine(), "Texture offset must be a constant expression",
+ unmangledName.c_str());
+ recover();
+ }
+ else
+ {
+ ASSERT(offsetConstantUnion->getBasicType() == EbtInt);
+ size_t size = offsetConstantUnion->getType().getObjectSize();
+ const TConstantUnion *values = offsetConstantUnion->getUnionArrayPointer();
+ for (size_t i = 0u; i < size; ++i)
+ {
+ int offsetValue = values[i].getIConst();
+ if (offsetValue > mMaxProgramTexelOffset || offsetValue < mMinProgramTexelOffset)
+ {
+ std::stringstream tokenStream;
+ tokenStream << offsetValue;
+ std::string token = tokenStream.str();
+ error(offset->getLine(), "Texture offset value out of valid range",
+ token.c_str());
+ recover();
+ }
+ }
+ }
+ }
+}
+
+TIntermTyped *TParseContext::addFunctionCallOrMethod(TFunction *fnCall,
+ TIntermNode *paramNode,
+ TIntermNode *thisNode,
+ const TSourceLoc &loc,
+ bool *fatalError)
+{
+ *fatalError = false;
+ TOperator op = fnCall->getBuiltInOp();
TIntermTyped *callNode = nullptr;
- if (op != EOpNull)
+ if (thisNode != nullptr)
+ {
+ TConstantUnion *unionArray = new TConstantUnion[1];
+ int arraySize = 0;
+ TIntermTyped *typedThis = thisNode->getAsTyped();
+ if (fnCall->getName() != "length")
+ {
+ error(loc, "invalid method", fnCall->getName().c_str());
+ recover();
+ }
+ else if (paramNode != nullptr)
+ {
+ error(loc, "method takes no parameters", "length");
+ recover();
+ }
+ else if (typedThis == nullptr || !typedThis->isArray())
+ {
+ error(loc, "length can only be called on arrays", "length");
+ recover();
+ }
+ else
+ {
+ arraySize = typedThis->getArraySize();
+ if (typedThis->getAsSymbolNode() == nullptr)
+ {
+ // This code path can be hit with expressions like these:
+ // (a = b).length()
+ // (func()).length()
+ // (int[3](0, 1, 2)).length()
+ // ESSL 3.00 section 5.9 defines expressions so that this is not actually a valid
+ // expression.
+ // It allows "An array name with the length method applied" in contrast to GLSL 4.4
+ // spec section 5.9 which allows "An array, vector or matrix expression with the
+ // length method applied".
+ error(loc, "length can only be called on array names, not on array expressions",
+ "length");
+ recover();
+ }
+ }
+ unionArray->setIConst(arraySize);
+ callNode =
+ intermediate.addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), loc);
+ }
+ else if (op != EOpNull)
{
//
// Then this should be a constructor.
@@ -3051,12 +3960,12 @@ TIntermTyped *TParseContext::addFunctionCallOrMethod(TFunction *fnCall, TIntermN
// Their parameters will be verified algorithmically.
//
TType type(EbtVoid, EbpUndefined); // use this to get the type back
- if (!constructorErrorCheck(loc, node, *fnCall, op, &type))
+ if (!constructorErrorCheck(loc, paramNode, *fnCall, op, &type))
{
//
// It's a constructor, of type 'type'.
//
- callNode = addConstructor(node, &type, op, fnCall, loc);
+ callNode = addConstructor(paramNode, &type, op, fnCall, loc);
}
if (callNode == nullptr)
@@ -3071,9 +3980,9 @@ TIntermTyped *TParseContext::addFunctionCallOrMethod(TFunction *fnCall, TIntermN
//
// Not a constructor. Find it in the symbol table.
//
- const TFunction* fnCandidate;
+ const TFunction *fnCandidate;
bool builtIn;
- fnCandidate = findFunction(loc, fnCall, shaderVersion, &builtIn);
+ fnCandidate = findFunction(loc, fnCall, mShaderVersion, &builtIn);
if (fnCandidate)
{
//
@@ -3095,47 +4004,75 @@ TIntermTyped *TParseContext::addFunctionCallOrMethod(TFunction *fnCall, TIntermN
//
// Treat it like a built-in unary operator.
//
- callNode = createUnaryMath(op, node->getAsTyped(), loc, &fnCandidate->getReturnType());
+ TIntermAggregate *paramAgg = paramNode->getAsAggregate();
+ paramNode = paramAgg->getSequence()->front();
+ callNode = createUnaryMath(op, paramNode->getAsTyped(), loc,
+ &fnCandidate->getReturnType());
if (callNode == nullptr)
{
std::stringstream extraInfoStream;
- extraInfoStream << "built in unary operator function. Type: "
- << static_cast<TIntermTyped*>(node)->getCompleteString();
+ extraInfoStream
+ << "built in unary operator function. Type: "
+ << static_cast<TIntermTyped *>(paramNode)->getCompleteString();
std::string extraInfo = extraInfoStream.str();
- error(node->getLine(), " wrong operand type", "Internal Error", extraInfo.c_str());
+ error(paramNode->getLine(), " wrong operand type", "Internal Error",
+ extraInfo.c_str());
*fatalError = true;
return nullptr;
}
}
else
{
- TIntermAggregate *aggregate = intermediate.setAggregateOperator(node, op, loc);
+ TIntermAggregate *aggregate =
+ intermediate.setAggregateOperator(paramNode, op, loc);
aggregate->setType(fnCandidate->getReturnType());
aggregate->setPrecisionFromChildren();
- callNode = aggregate;
+ if (aggregate->areChildrenConstQualified())
+ {
+ aggregate->getTypePointer()->setQualifier(EvqConst);
+ }
// Some built-in functions have out parameters too.
functionCallLValueErrorCheck(fnCandidate, aggregate);
+
+ // See if we can constant fold a built-in. Note that this may be possible even
+ // if it is not const-qualified.
+ TIntermTyped *foldedNode = intermediate.foldAggregateBuiltIn(aggregate);
+ if (foldedNode)
+ {
+ callNode = foldedNode;
+ }
+ else
+ {
+ callNode = aggregate;
+ }
}
}
else
{
// This is a real function call
-
- TIntermAggregate *aggregate = intermediate.setAggregateOperator(node, EOpFunctionCall, loc);
+ TIntermAggregate *aggregate =
+ intermediate.setAggregateOperator(paramNode, EOpFunctionCall, loc);
aggregate->setType(fnCandidate->getReturnType());
- // this is how we know whether the given function is a builtIn function or a user defined function
- // if builtIn == false, it's a userDefined -> could be an overloaded builtIn function also
+ // this is how we know whether the given function is a builtIn function or a user
+ // defined function
+ // if builtIn == false, it's a userDefined -> could be an overloaded
+ // builtIn function also
// if builtIn == true, it's definitely a builtIn function with EOpNull
if (!builtIn)
aggregate->setUserDefined();
aggregate->setName(fnCandidate->getMangledName());
+ aggregate->setFunctionId(fnCandidate->getUniqueId());
// This needs to happen after the name is set
if (builtIn)
+ {
aggregate->setBuiltInFunctionPrecision();
+ checkTextureOffsetConst(aggregate);
+ }
+
callNode = aggregate;
functionCallLValueErrorCheck(fnCandidate, aggregate);
@@ -3145,24 +4082,52 @@ TIntermTyped *TParseContext::addFunctionCallOrMethod(TFunction *fnCall, TIntermN
{
// error message was put out by findFunction()
// Put on a dummy node for error recovery
- ConstantUnion *unionArray = new ConstantUnion[1];
+ TConstantUnion *unionArray = new TConstantUnion[1];
unionArray->setFConst(0.0f);
- callNode = intermediate.addConstantUnion(unionArray, TType(EbtFloat, EbpUndefined, EvqConst), loc);
+ callNode = intermediate.addConstantUnion(unionArray,
+ TType(EbtFloat, EbpUndefined, EvqConst), loc);
recover();
}
}
- delete fnCall;
return callNode;
}
+TIntermTyped *TParseContext::addTernarySelection(TIntermTyped *cond,
+ TIntermTyped *trueBlock,
+ TIntermTyped *falseBlock,
+ const TSourceLoc &loc)
+{
+ if (boolErrorCheck(loc, cond))
+ recover();
+
+ if (trueBlock->getType() != falseBlock->getType())
+ {
+ binaryOpError(loc, ":", trueBlock->getCompleteString(), falseBlock->getCompleteString());
+ recover();
+ return falseBlock;
+ }
+ // ESSL1 sections 5.2 and 5.7:
+ // ESSL3 section 5.7:
+ // Ternary operator is not among the operators allowed for structures/arrays.
+ if (trueBlock->isArray() || trueBlock->getBasicType() == EbtStruct)
+ {
+ error(loc, "ternary operator is not allowed for structures or arrays", ":");
+ recover();
+ return falseBlock;
+ }
+ return intermediate.addSelection(cond, trueBlock, falseBlock, loc);
+}
//
// Parse an array of strings using yyparse.
//
// Returns 0 for success.
//
-int PaParseStrings(size_t count, const char* const string[], const int length[],
- TParseContext* context) {
+int PaParseStrings(size_t count,
+ const char *const string[],
+ const int length[],
+ TParseContext *context)
+{
if ((count == 0) || (string == NULL))
return 1;
@@ -3177,6 +4142,3 @@ int PaParseStrings(size_t count, const char* const string[], const int length[],
return (error == 0) && (context->numErrors() == 0) ? 0 : 1;
}
-
-
-
diff --git a/src/3rdparty/angle/src/compiler/translator/ParseContext.h b/src/3rdparty/angle/src/compiler/translator/ParseContext.h
index b6a0f4a637..1eaf1e5b42 100644
--- a/src/3rdparty/angle/src/compiler/translator/ParseContext.h
+++ b/src/3rdparty/angle/src/compiler/translator/ParseContext.h
@@ -13,7 +13,8 @@
#include "compiler/translator/SymbolTable.h"
#include "compiler/preprocessor/Preprocessor.h"
-struct TMatrixFields {
+struct TMatrixFields
+{
bool wholeRow;
bool wholeCol;
int row;
@@ -24,137 +25,275 @@ struct TMatrixFields {
// The following are extra variables needed during parsing, grouped together so
// they can be passed to the parser without needing a global.
//
-struct TParseContext {
- TParseContext(TSymbolTable& symt, TExtensionBehavior& ext, TIntermediate& interm, sh::GLenum type, ShShaderSpec spec, int options, bool checksPrecErrors, TInfoSink& is, bool debugShaderPrecisionSupported) :
- intermediate(interm),
- symbolTable(symt),
- shaderType(type),
- shaderSpec(spec),
- compileOptions(options),
- treeRoot(0),
- mLoopNestingLevel(0),
- structNestingLevel(0),
- mSwitchNestingLevel(0),
- currentFunctionType(NULL),
- mFunctionReturnsValue(false),
- checksPrecisionErrors(checksPrecErrors),
- fragmentPrecisionHigh(false),
- defaultMatrixPacking(EmpColumnMajor),
- defaultBlockStorage(EbsShared),
- diagnostics(is),
- shaderVersion(100),
- directiveHandler(ext, diagnostics, shaderVersion, debugShaderPrecisionSupported),
- preprocessor(&diagnostics, &directiveHandler),
- scanner(NULL) { }
- TIntermediate& intermediate; // to hold and build a parse tree
- TSymbolTable& symbolTable; // symbol table that goes with the language currently being parsed
- sh::GLenum shaderType; // vertex or fragment language (future: pack or unpack)
- ShShaderSpec shaderSpec; // The language specification compiler conforms to - GLES2 or WebGL.
- int shaderVersion;
- int compileOptions;
- TIntermNode* treeRoot; // root of parse tree being created
- int mLoopNestingLevel; // 0 if outside all loops
- int structNestingLevel; // incremented while parsing a struct declaration
- int mSwitchNestingLevel; // 0 if outside all switch statements
- const TType* currentFunctionType; // the return type of the function that's currently being parsed
- bool mFunctionReturnsValue; // true if a non-void function has a return
- bool checksPrecisionErrors; // true if an error will be generated when a variable is declared without precision, explicit or implicit.
- bool fragmentPrecisionHigh; // true if highp precision is supported in the fragment language.
- TLayoutMatrixPacking defaultMatrixPacking;
- TLayoutBlockStorage defaultBlockStorage;
- TString HashErrMsg;
- TDiagnostics diagnostics;
- TDirectiveHandler directiveHandler;
- pp::Preprocessor preprocessor;
- void* scanner;
-
- int getShaderVersion() const { return shaderVersion; }
- int numErrors() const { return diagnostics.numErrors(); }
- TInfoSink& infoSink() { return diagnostics.infoSink(); }
- void error(const TSourceLoc& loc, const char *reason, const char* token,
- const char* extraInfo="");
- void warning(const TSourceLoc& loc, const char* reason, const char* token,
- const char* extraInfo="");
- void trace(const char* str);
+class TParseContext : angle::NonCopyable
+{
+ public:
+ TParseContext(TSymbolTable &symt,
+ TExtensionBehavior &ext,
+ TIntermediate &interm,
+ sh::GLenum type,
+ ShShaderSpec spec,
+ int options,
+ bool checksPrecErrors,
+ TInfoSink &is,
+ const ShBuiltInResources &resources)
+ : intermediate(interm),
+ symbolTable(symt),
+ mDeferredSingleDeclarationErrorCheck(false),
+ mShaderType(type),
+ mShaderSpec(spec),
+ mShaderVersion(100),
+ mTreeRoot(nullptr),
+ mLoopNestingLevel(0),
+ mStructNestingLevel(0),
+ mSwitchNestingLevel(0),
+ mCurrentFunctionType(nullptr),
+ mFunctionReturnsValue(false),
+ mChecksPrecisionErrors(checksPrecErrors),
+ mFragmentPrecisionHighOnESSL1(false),
+ mDefaultMatrixPacking(EmpColumnMajor),
+ mDefaultBlockStorage(EbsShared),
+ mDiagnostics(is),
+ mDirectiveHandler(ext,
+ mDiagnostics,
+ mShaderVersion,
+ mShaderType,
+ resources.WEBGL_debug_shader_precision == 1),
+ mPreprocessor(&mDiagnostics, &mDirectiveHandler),
+ mScanner(nullptr),
+ mUsesFragData(false),
+ mUsesFragColor(false),
+ mUsesSecondaryOutputs(false),
+ mMinProgramTexelOffset(resources.MinProgramTexelOffset),
+ mMaxProgramTexelOffset(resources.MaxProgramTexelOffset)
+ {
+ }
+
+ const pp::Preprocessor &getPreprocessor() const { return mPreprocessor; }
+ pp::Preprocessor &getPreprocessor() { return mPreprocessor; }
+ void *getScanner() const { return mScanner; }
+ void setScanner(void *scanner) { mScanner = scanner; }
+ int getShaderVersion() const { return mShaderVersion; }
+ sh::GLenum getShaderType() const { return mShaderType; }
+ ShShaderSpec getShaderSpec() const { return mShaderSpec; }
+ int numErrors() const { return mDiagnostics.numErrors(); }
+ TInfoSink &infoSink() { return mDiagnostics.infoSink(); }
+ void error(const TSourceLoc &loc, const char *reason, const char *token,
+ const char *extraInfo="");
+ void warning(const TSourceLoc &loc, const char *reason, const char *token,
+ const char *extraInfo="");
+
+ // If isError is false, a warning will be reported instead.
+ void outOfRangeError(bool isError,
+ const TSourceLoc &loc,
+ const char *reason,
+ const char *token,
+ const char *extraInfo = "");
+
void recover();
+ TIntermNode *getTreeRoot() const { return mTreeRoot; }
+ void setTreeRoot(TIntermNode *treeRoot) { mTreeRoot = treeRoot; }
+
+ bool getFragmentPrecisionHigh() const
+ {
+ return mFragmentPrecisionHighOnESSL1 || mShaderVersion >= 300;
+ }
+ void setFragmentPrecisionHighOnESSL1(bool fragmentPrecisionHigh)
+ {
+ mFragmentPrecisionHighOnESSL1 = fragmentPrecisionHigh;
+ }
+
+ void setLoopNestingLevel(int loopNestintLevel)
+ {
+ mLoopNestingLevel = loopNestintLevel;
+ }
+
+ void incrLoopNestingLevel() { ++mLoopNestingLevel; }
+ void decrLoopNestingLevel() { --mLoopNestingLevel; }
+
+ void incrSwitchNestingLevel() { ++mSwitchNestingLevel; }
+ void decrSwitchNestingLevel() { --mSwitchNestingLevel; }
// This method is guaranteed to succeed, even if no variable with 'name' exists.
const TVariable *getNamedVariable(const TSourceLoc &location, const TString *name, const TSymbol *symbol);
+ TIntermTyped *parseVariableIdentifier(const TSourceLoc &location,
+ const TString *name,
+ const TSymbol *symbol);
- bool parseVectorFields(const TString&, int vecSize, TVectorFields&, const TSourceLoc& line);
- bool parseMatrixFields(const TString&, int matCols, int matRows, TMatrixFields&, const TSourceLoc& line);
-
- bool reservedErrorCheck(const TSourceLoc& line, const TString& identifier);
- void assignError(const TSourceLoc& line, const char* op, TString left, TString right);
- void unaryOpError(const TSourceLoc& line, const char* op, TString operand);
- void binaryOpError(const TSourceLoc& line, const char* op, TString left, TString right);
- bool precisionErrorCheck(const TSourceLoc& line, TPrecision precision, TBasicType type);
- bool lValueErrorCheck(const TSourceLoc& line, const char* op, TIntermTyped*);
- bool constErrorCheck(TIntermTyped* node);
- bool integerErrorCheck(TIntermTyped* node, const char* token);
- bool globalErrorCheck(const TSourceLoc& line, bool global, const char* token);
- bool constructorErrorCheck(const TSourceLoc& line, TIntermNode*, TFunction&, TOperator, TType*);
- bool arraySizeErrorCheck(const TSourceLoc& line, TIntermTyped* expr, int& size);
- bool arrayQualifierErrorCheck(const TSourceLoc& line, TPublicType type);
- bool arrayTypeErrorCheck(const TSourceLoc& line, TPublicType type);
- bool arrayErrorCheck(const TSourceLoc& line, const TString& identifier, const TPublicType &type, TVariable*& variable);
- bool voidErrorCheck(const TSourceLoc&, const TString&, const TPublicType&);
+ bool parseVectorFields(const TString&, int vecSize, TVectorFields&, const TSourceLoc &line);
+
+ bool reservedErrorCheck(const TSourceLoc &line, const TString &identifier);
+ void assignError(const TSourceLoc &line, const char *op, TString left, TString right);
+ void unaryOpError(const TSourceLoc &line, const char *op, TString operand);
+ void binaryOpError(const TSourceLoc &line, const char *op, TString left, TString right);
+ bool precisionErrorCheck(const TSourceLoc &line, TPrecision precision, TBasicType type);
+ bool lValueErrorCheck(const TSourceLoc &line, const char *op, TIntermTyped*);
+ bool constErrorCheck(TIntermTyped *node);
+ bool integerErrorCheck(TIntermTyped *node, const char *token);
+ bool globalErrorCheck(const TSourceLoc &line, bool global, const char *token);
+ bool constructorErrorCheck(const TSourceLoc &line,
+ TIntermNode *argumentsNode,
+ TFunction &function,
+ TOperator op,
+ TType *type);
+ bool arraySizeErrorCheck(const TSourceLoc &line, TIntermTyped *expr, int &size);
+ bool arrayQualifierErrorCheck(const TSourceLoc &line, const TPublicType &type);
+ bool arrayTypeErrorCheck(const TSourceLoc &line, const TPublicType &type);
+ bool voidErrorCheck(const TSourceLoc &line, const TString &identifier, const TBasicType &type);
bool boolErrorCheck(const TSourceLoc&, const TIntermTyped*);
bool boolErrorCheck(const TSourceLoc&, const TPublicType&);
- bool samplerErrorCheck(const TSourceLoc& line, const TPublicType& pType, const char* reason);
- bool structQualifierErrorCheck(const TSourceLoc& line, const TPublicType& pType);
- bool locationDeclaratorListCheck(const TSourceLoc& line, const TPublicType &pType);
- bool parameterSamplerErrorCheck(const TSourceLoc& line, TQualifier qualifier, const TType& type);
- bool nonInitConstErrorCheck(const TSourceLoc& line, const TString& identifier, TPublicType& type, bool array);
- bool nonInitErrorCheck(const TSourceLoc& line, const TString& identifier, const TPublicType& type, TVariable*& variable);
- bool paramErrorCheck(const TSourceLoc& line, TQualifier qualifier, TQualifier paramQualifier, TType* type);
- bool extensionErrorCheck(const TSourceLoc& line, const TString&);
- bool singleDeclarationErrorCheck(TPublicType &publicType, const TSourceLoc& identifierLocation, const TString &identifier);
- bool layoutLocationErrorCheck(const TSourceLoc& location, const TLayoutQualifier &layoutQualifier);
+ bool samplerErrorCheck(const TSourceLoc &line, const TPublicType &pType, const char *reason);
+ bool locationDeclaratorListCheck(const TSourceLoc &line, const TPublicType &pType);
+ bool parameterSamplerErrorCheck(const TSourceLoc &line, TQualifier qualifier, const TType &type);
+ bool paramErrorCheck(const TSourceLoc &line, TQualifier qualifier, TQualifier paramQualifier, TType *type);
+ bool extensionErrorCheck(const TSourceLoc &line, const TString&);
+ bool singleDeclarationErrorCheck(const TPublicType &publicType, const TSourceLoc &identifierLocation);
+ bool layoutLocationErrorCheck(const TSourceLoc &location, const TLayoutQualifier &layoutQualifier);
bool functionCallLValueErrorCheck(const TFunction *fnCandidate, TIntermAggregate *);
+ void es3InvariantErrorCheck(const TQualifier qualifier, const TSourceLoc &invariantLocation);
+ void es3InputOutputTypeCheck(const TQualifier qualifier,
+ const TPublicType &type,
+ const TSourceLoc &qualifierLocation);
+
+ const TPragma &pragma() const { return mDirectiveHandler.pragma(); }
+ const TExtensionBehavior &extensionBehavior() const { return mDirectiveHandler.extensionBehavior(); }
+ bool supportsExtension(const char *extension);
+ bool isExtensionEnabled(const char *extension) const;
+ void handleExtensionDirective(const TSourceLoc &loc, const char *extName, const char *behavior);
+ void handlePragmaDirective(const TSourceLoc &loc, const char *name, const char *value, bool stdgl);
+
+ bool containsSampler(const TType &type);
+ const TFunction* findFunction(
+ const TSourceLoc &line, TFunction *pfnCall, int inputShaderVersion, bool *builtIn = 0);
+ bool executeInitializer(const TSourceLoc &line,
+ const TString &identifier,
+ const TPublicType &pType,
+ TIntermTyped *initializer,
+ TIntermNode **intermNode);
+
+ TPublicType addFullySpecifiedType(TQualifier qualifier,
+ bool invariant,
+ TLayoutQualifier layoutQualifier,
+ const TPublicType &typeSpecifier);
+
+ TIntermAggregate *parseSingleDeclaration(TPublicType &publicType,
+ const TSourceLoc &identifierOrTypeLocation,
+ const TString &identifier);
+ TIntermAggregate *parseSingleArrayDeclaration(TPublicType &publicType,
+ const TSourceLoc &identifierLocation,
+ const TString &identifier,
+ const TSourceLoc &indexLocation,
+ TIntermTyped *indexExpression);
+ TIntermAggregate *parseSingleInitDeclaration(const TPublicType &publicType,
+ const TSourceLoc &identifierLocation,
+ const TString &identifier,
+ const TSourceLoc &initLocation,
+ TIntermTyped *initializer);
+
+ // Parse a declaration like "type a[n] = initializer"
+ // Note that this does not apply to declarations like "type[n] a = initializer"
+ TIntermAggregate *parseSingleArrayInitDeclaration(TPublicType &publicType,
+ const TSourceLoc &identifierLocation,
+ const TString &identifier,
+ const TSourceLoc &indexLocation,
+ TIntermTyped *indexExpression,
+ const TSourceLoc &initLocation,
+ TIntermTyped *initializer);
+
+ TIntermAggregate *parseInvariantDeclaration(const TSourceLoc &invariantLoc,
+ const TSourceLoc &identifierLoc,
+ const TString *identifier,
+ const TSymbol *symbol);
+
+ TIntermAggregate *parseDeclarator(TPublicType &publicType,
+ TIntermAggregate *aggregateDeclaration,
+ const TSourceLoc &identifierLocation,
+ const TString &identifier);
+ TIntermAggregate *parseArrayDeclarator(TPublicType &publicType,
+ TIntermAggregate *aggregateDeclaration,
+ const TSourceLoc &identifierLocation,
+ const TString &identifier,
+ const TSourceLoc &arrayLocation,
+ TIntermTyped *indexExpression);
+ TIntermAggregate *parseInitDeclarator(const TPublicType &publicType,
+ TIntermAggregate *aggregateDeclaration,
+ const TSourceLoc &identifierLocation,
+ const TString &identifier,
+ const TSourceLoc &initLocation,
+ TIntermTyped *initializer);
+
+ // Parse a declarator like "a[n] = initializer"
+ TIntermAggregate *parseArrayInitDeclarator(const TPublicType &publicType,
+ TIntermAggregate *aggregateDeclaration,
+ const TSourceLoc &identifierLocation,
+ const TString &identifier,
+ const TSourceLoc &indexLocation,
+ TIntermTyped *indexExpression,
+ const TSourceLoc &initLocation,
+ TIntermTyped *initializer);
- const TPragma& pragma() const { return directiveHandler.pragma(); }
- const TExtensionBehavior& extensionBehavior() const { return directiveHandler.extensionBehavior(); }
- bool supportsExtension(const char* extension);
- bool isExtensionEnabled(const char* extension) const;
- void handleExtensionDirective(const TSourceLoc& loc, const char* extName, const char* behavior);
- void handlePragmaDirective(const TSourceLoc& loc, const char* name, const char* value, bool stdgl);
-
- bool containsSampler(TType& type);
- bool areAllChildConst(TIntermAggregate* aggrNode);
- const TFunction* findFunction(const TSourceLoc& line, TFunction* pfnCall, int inputShaderVersion, bool *builtIn = 0);
- bool executeInitializer(const TSourceLoc& line, const TString& identifier, TPublicType& pType,
- TIntermTyped* initializer, TIntermNode*& intermNode, TVariable* variable = 0);
-
- TPublicType addFullySpecifiedType(TQualifier qualifier, const TPublicType& typeSpecifier);
- TPublicType addFullySpecifiedType(TQualifier qualifier, TLayoutQualifier layoutQualifier, const TPublicType& typeSpecifier);
- TIntermAggregate* parseSingleDeclaration(TPublicType &publicType, const TSourceLoc& identifierLocation, const TString &identifier);
- TIntermAggregate* parseSingleArrayDeclaration(TPublicType &publicType, const TSourceLoc& identifierLocation, const TString &identifier, const TSourceLoc& indexLocation, TIntermTyped *indexExpression);
- TIntermAggregate* parseSingleInitDeclaration(TPublicType &publicType, const TSourceLoc& identifierLocation, const TString &identifier, const TSourceLoc& initLocation, TIntermTyped *initializer);
- TIntermAggregate* parseInvariantDeclaration(const TSourceLoc &invariantLoc, const TSourceLoc &identifierLoc, const TString *identifier, const TSymbol *symbol);
-
- TIntermAggregate* parseDeclarator(TPublicType &publicType, TIntermAggregate *aggregateDeclaration, TSymbol *identifierSymbol, const TSourceLoc& identifierLocation, const TString &identifier);
- TIntermAggregate* parseArrayDeclarator(TPublicType &publicType, const TSourceLoc& identifierLocation, const TString &identifier, const TSourceLoc& arrayLocation, TIntermNode *declaratorList, TIntermTyped *indexExpression);
- TIntermAggregate* parseInitDeclarator(TPublicType &publicType, TIntermAggregate *declaratorList, const TSourceLoc& identifierLocation, const TString &identifier, const TSourceLoc& initLocation, TIntermTyped *initializer);
void parseGlobalLayoutQualifier(const TPublicType &typeQualifier);
- TFunction *addConstructorFunc(TPublicType publicType);
- TIntermTyped* addConstructor(TIntermNode*, TType*, TOperator, TFunction*, const TSourceLoc&);
- TIntermTyped* foldConstConstructor(TIntermAggregate* aggrNode, const TType& type);
- TIntermTyped* addConstVectorNode(TVectorFields&, TIntermTyped*, const TSourceLoc&);
- TIntermTyped* addConstMatrixNode(int , TIntermTyped*, const TSourceLoc&);
- TIntermTyped* addConstArrayNode(int index, TIntermTyped* node, const TSourceLoc& line);
- TIntermTyped* addConstStruct(const TString &identifier, TIntermTyped *node, const TSourceLoc& line);
- TIntermTyped* addIndexExpression(TIntermTyped *baseExpression, const TSourceLoc& location, TIntermTyped *indexExpression);
- TIntermTyped* addFieldSelectionExpression(TIntermTyped *baseExpression, const TSourceLoc& dotLocation, const TString &fieldString, const TSourceLoc& fieldLocation);
-
- TFieldList *addStructDeclaratorList(const TPublicType& typeSpecifier, TFieldList *fieldList);
- TPublicType addStructure(const TSourceLoc& structLine, const TSourceLoc& nameLine, const TString *structName, TFieldList* fieldList);
-
- TIntermAggregate* addInterfaceBlock(const TPublicType& typeQualifier, const TSourceLoc& nameLine, const TString& blockName, TFieldList* fieldList,
- const TString* instanceName, const TSourceLoc& instanceLine, TIntermTyped* arrayIndex, const TSourceLoc& arrayIndexLine);
-
- TLayoutQualifier parseLayoutQualifier(const TString &qualifierType, const TSourceLoc& qualifierTypeLine);
- TLayoutQualifier parseLayoutQualifier(const TString &qualifierType, const TSourceLoc& qualifierTypeLine, const TString &intValueString, int intValue, const TSourceLoc& intValueLine);
+ TIntermAggregate *addFunctionPrototypeDeclaration(const TFunction &function,
+ const TSourceLoc &location);
+ TIntermAggregate *addFunctionDefinition(const TFunction &function,
+ TIntermAggregate *functionPrototype,
+ TIntermAggregate *functionBody,
+ const TSourceLoc &location);
+ void parseFunctionPrototype(const TSourceLoc &location,
+ TFunction *function,
+ TIntermAggregate **aggregateOut);
+ TFunction *parseFunctionDeclarator(const TSourceLoc &location,
+ TFunction *function);
+ TFunction *addConstructorFunc(const TPublicType &publicType);
+ TIntermTyped *addConstructor(TIntermNode *arguments,
+ TType *type,
+ TOperator op,
+ TFunction *fnCall,
+ const TSourceLoc &line);
+ TIntermTyped *addConstVectorNode(TVectorFields &fields,
+ TIntermConstantUnion *node,
+ const TSourceLoc &line,
+ bool outOfRangeIndexIsError);
+ TIntermTyped *addConstMatrixNode(int index,
+ TIntermConstantUnion *node,
+ const TSourceLoc &line,
+ bool outOfRangeIndexIsError);
+ TIntermTyped *addConstArrayNode(int index,
+ TIntermConstantUnion *node,
+ const TSourceLoc &line,
+ bool outOfRangeIndexIsError);
+ TIntermTyped *addConstStruct(
+ const TString &identifier, TIntermTyped *node, const TSourceLoc& line);
+ TIntermTyped *addIndexExpression(TIntermTyped *baseExpression,
+ const TSourceLoc& location,
+ TIntermTyped *indexExpression);
+ TIntermTyped* addFieldSelectionExpression(TIntermTyped *baseExpression,
+ const TSourceLoc &dotLocation,
+ const TString &fieldString,
+ const TSourceLoc &fieldLocation);
+
+ TFieldList *addStructDeclaratorList(const TPublicType &typeSpecifier, TFieldList *fieldList);
+ TPublicType addStructure(const TSourceLoc &structLine,
+ const TSourceLoc &nameLine,
+ const TString *structName,
+ TFieldList *fieldList);
+
+ TIntermAggregate* addInterfaceBlock(const TPublicType &typeQualifier,
+ const TSourceLoc &nameLine,
+ const TString &blockName,
+ TFieldList *fieldList,
+ const TString *instanceName,
+ const TSourceLoc &instanceLine,
+ TIntermTyped *arrayIndex,
+ const TSourceLoc& arrayIndexLine);
+
+ TLayoutQualifier parseLayoutQualifier(
+ const TString &qualifierType, const TSourceLoc &qualifierTypeLine);
+ TLayoutQualifier parseLayoutQualifier(const TString &qualifierType,
+ const TSourceLoc &qualifierTypeLine,
+ const TString &intValueString,
+ int intValue,
+ const TSourceLoc &intValueLine);
TLayoutQualifier joinLayoutQualifiers(TLayoutQualifier leftQualifier, TLayoutQualifier rightQualifier);
TPublicType joinInterpolationQualifiers(const TSourceLoc &interpolationLoc, TQualifier interpolationQualifier,
const TSourceLoc &storageLoc, TQualifier storageQualifier);
@@ -162,46 +301,92 @@ struct TParseContext {
// Performs an error check for embedded struct declarations.
// Returns true if an error was raised due to the declaration of
// this struct.
- bool enterStructDeclaration(const TSourceLoc& line, const TString& identifier);
+ bool enterStructDeclaration(const TSourceLoc &line, const TString &identifier);
void exitStructDeclaration();
- bool structNestingErrorCheck(const TSourceLoc& line, const TField& field);
+ bool structNestingErrorCheck(const TSourceLoc &line, const TField &field);
TIntermSwitch *addSwitch(TIntermTyped *init, TIntermAggregate *statementList, const TSourceLoc &loc);
TIntermCase *addCase(TIntermTyped *condition, const TSourceLoc &loc);
TIntermCase *addDefault(const TSourceLoc &loc);
- TIntermTyped *addUnaryMath(TOperator op, TIntermTyped *child, const TSourceLoc &);
- TIntermTyped *addUnaryMathLValue(TOperator op, TIntermTyped *child, const TSourceLoc &);
- TIntermTyped *addBinaryMath(TOperator op, TIntermTyped *left, TIntermTyped *right,
- const TSourceLoc &);
- TIntermTyped *addBinaryMathBooleanResult(TOperator op, TIntermTyped *left, TIntermTyped *right,
- const TSourceLoc &);
- TIntermTyped *addAssign(TOperator op, TIntermTyped *left, TIntermTyped *right,
- const TSourceLoc &loc);
+ TIntermTyped *addUnaryMath(TOperator op, TIntermTyped *child, const TSourceLoc &loc);
+ TIntermTyped *addUnaryMathLValue(TOperator op, TIntermTyped *child, const TSourceLoc &loc);
+ TIntermTyped *addBinaryMath(
+ TOperator op, TIntermTyped *left, TIntermTyped *right, const TSourceLoc &loc);
+ TIntermTyped *addBinaryMathBooleanResult(
+ TOperator op, TIntermTyped *left, TIntermTyped *right, const TSourceLoc &loc);
+ TIntermTyped *addAssign(
+ TOperator op, TIntermTyped *left, TIntermTyped *right, const TSourceLoc &loc);
+
+ TIntermTyped *addComma(TIntermTyped *left, TIntermTyped *right, const TSourceLoc &loc);
TIntermBranch *addBranch(TOperator op, const TSourceLoc &loc);
TIntermBranch *addBranch(TOperator op, TIntermTyped *returnValue, const TSourceLoc &loc);
- TIntermTyped *addFunctionCallOrMethod(TFunction *fnCall, TIntermNode *node,
- const TSourceLoc &loc, bool *fatalError);
+ void checkTextureOffsetConst(TIntermAggregate *functionCall);
+ TIntermTyped *addFunctionCallOrMethod(TFunction *fnCall,
+ TIntermNode *paramNode,
+ TIntermNode *thisNode,
+ const TSourceLoc &loc,
+ bool *fatalError);
+
+ TIntermTyped *addTernarySelection(
+ TIntermTyped *cond, TIntermTyped *trueBlock, TIntermTyped *falseBlock, const TSourceLoc &line);
+
+ // TODO(jmadill): make these private
+ TIntermediate &intermediate; // to hold and build a parse tree
+ TSymbolTable &symbolTable; // symbol table that goes with the language currently being parsed
private:
- TIntermTyped *addBinaryMathInternal(TOperator op, TIntermTyped *left, TIntermTyped *right,
- const TSourceLoc &loc);
- TIntermTyped *createAssign(TOperator op, TIntermTyped *left, TIntermTyped *right,
- const TSourceLoc &loc);
+ bool declareVariable(const TSourceLoc &line, const TString &identifier, const TType &type, TVariable **variable);
+
+ bool nonInitErrorCheck(const TSourceLoc &line, const TString &identifier, TPublicType *type);
+
+ TIntermTyped *addBinaryMathInternal(
+ TOperator op, TIntermTyped *left, TIntermTyped *right, const TSourceLoc &loc);
+ TIntermTyped *createAssign(
+ TOperator op, TIntermTyped *left, TIntermTyped *right, const TSourceLoc &loc);
// The funcReturnType parameter is expected to be non-null when the operation is a built-in function.
// It is expected to be null for other unary operators.
- TIntermTyped *createUnaryMath(TOperator op, TIntermTyped *child, const TSourceLoc &loc,
- const TType *funcReturnType);
+ TIntermTyped *createUnaryMath(
+ TOperator op, TIntermTyped *child, const TSourceLoc &loc, const TType *funcReturnType);
// Return true if the checks pass
- bool binaryOpCommonCheck(TOperator op, TIntermTyped *left, TIntermTyped *right,
- const TSourceLoc &loc);
+ bool binaryOpCommonCheck(
+ TOperator op, TIntermTyped *left, TIntermTyped *right, const TSourceLoc &loc);
+
+ // Set to true when the last/current declarator list was started with an empty declaration.
+ bool mDeferredSingleDeclarationErrorCheck;
+
+ sh::GLenum mShaderType; // vertex or fragment language (future: pack or unpack)
+ ShShaderSpec mShaderSpec; // The language specification compiler conforms to - GLES2 or WebGL.
+ int mShaderVersion;
+ TIntermNode *mTreeRoot; // root of parse tree being created
+ int mLoopNestingLevel; // 0 if outside all loops
+ int mStructNestingLevel; // incremented while parsing a struct declaration
+ int mSwitchNestingLevel; // 0 if outside all switch statements
+ const TType *mCurrentFunctionType; // the return type of the function that's currently being parsed
+ bool mFunctionReturnsValue; // true if a non-void function has a return
+ bool mChecksPrecisionErrors; // true if an error will be generated when a variable is declared without precision, explicit or implicit.
+ bool mFragmentPrecisionHighOnESSL1; // true if highp precision is supported when compiling
+ // ESSL1.
+ TLayoutMatrixPacking mDefaultMatrixPacking;
+ TLayoutBlockStorage mDefaultBlockStorage;
+ TString mHashErrMsg;
+ TDiagnostics mDiagnostics;
+ TDirectiveHandler mDirectiveHandler;
+ pp::Preprocessor mPreprocessor;
+ void *mScanner;
+ bool mUsesFragData; // track if we are using both gl_FragData and gl_FragColor
+ bool mUsesFragColor;
+ bool mUsesSecondaryOutputs; // Track if we are using either gl_SecondaryFragData or
+ // gl_Secondary FragColor or both.
+ int mMinProgramTexelOffset;
+ int mMaxProgramTexelOffset;
};
-int PaParseStrings(size_t count, const char* const string[], const int length[],
- TParseContext* context);
+int PaParseStrings(
+ size_t count, const char *const string[], const int length[], TParseContext *context);
#endif // COMPILER_TRANSLATOR_PARSECONTEXT_H_
diff --git a/src/3rdparty/angle/src/compiler/translator/PoolAlloc.h b/src/3rdparty/angle/src/compiler/translator/PoolAlloc.h
index 6cd8d30114..dab2926c90 100644
--- a/src/3rdparty/angle/src/compiler/translator/PoolAlloc.h
+++ b/src/3rdparty/angle/src/compiler/translator/PoolAlloc.h
@@ -247,18 +247,13 @@ public:
pointer address(reference x) const { return &x; }
const_pointer address(const_reference x) const { return &x; }
- pool_allocator() : allocator(GetGlobalPoolAllocator()) { }
- pool_allocator(TPoolAllocator& a) : allocator(&a) { }
- pool_allocator(const pool_allocator<T>& p) : allocator(p.allocator) { }
-
- template <class Other>
- pool_allocator<T>& operator=(const pool_allocator<Other>& p) {
- allocator = p.allocator;
- return *this;
- }
+ pool_allocator() { }
template<class Other>
- pool_allocator(const pool_allocator<Other>& p) : allocator(&p.getAllocator()) { }
+ pool_allocator(const pool_allocator<Other>& p) { }
+
+ template <class Other>
+ pool_allocator<T>& operator=(const pool_allocator<Other>& p) { return *this; }
#if defined(__SUNPRO_CC) && !defined(_RWSTD_ALLOCATOR)
// libCStd on some platforms have a different allocate/deallocate interface.
@@ -284,17 +279,13 @@ public:
void construct(pointer p, const T& val) { new ((void *)p) T(val); }
void destroy(pointer p) { p->T::~T(); }
- bool operator==(const pool_allocator& rhs) const { return &getAllocator() == &rhs.getAllocator(); }
- bool operator!=(const pool_allocator& rhs) const { return &getAllocator() != &rhs.getAllocator(); }
+ bool operator==(const pool_allocator& rhs) const { return true; }
+ bool operator!=(const pool_allocator& rhs) const { return false; }
size_type max_size() const { return static_cast<size_type>(-1) / sizeof(T); }
size_type max_size(int size) const { return static_cast<size_type>(-1) / size; }
- void setAllocator(TPoolAllocator* a) { allocator = a; }
- TPoolAllocator& getAllocator() const { return *allocator; }
-
-protected:
- TPoolAllocator* allocator;
+ TPoolAllocator& getAllocator() const { return *GetGlobalPoolAllocator(); }
};
#endif // COMPILER_TRANSLATOR_POOLALLOC_H_
diff --git a/src/3rdparty/angle/src/compiler/translator/PruneEmptyDeclarations.cpp b/src/3rdparty/angle/src/compiler/translator/PruneEmptyDeclarations.cpp
new file mode 100644
index 0000000000..ef62dbfce7
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/translator/PruneEmptyDeclarations.cpp
@@ -0,0 +1,81 @@
+//
+// 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 PruneEmptyDeclarations function prunes unnecessary empty declarations and declarators from the AST.
+
+#include "compiler/translator/PruneEmptyDeclarations.h"
+
+#include "compiler/translator/IntermNode.h"
+
+namespace
+{
+
+class PruneEmptyDeclarationsTraverser : private TIntermTraverser
+{
+ public:
+ static void apply(TIntermNode *root);
+ private:
+ PruneEmptyDeclarationsTraverser();
+ bool visitAggregate(Visit, TIntermAggregate *node) override;
+};
+
+void PruneEmptyDeclarationsTraverser::apply(TIntermNode *root)
+{
+ PruneEmptyDeclarationsTraverser prune;
+ root->traverse(&prune);
+ prune.updateTree();
+}
+
+PruneEmptyDeclarationsTraverser::PruneEmptyDeclarationsTraverser()
+ : TIntermTraverser(true, false, false)
+{
+}
+
+bool PruneEmptyDeclarationsTraverser::visitAggregate(Visit, TIntermAggregate *node)
+{
+ if (node->getOp() == EOpDeclaration)
+ {
+ TIntermSequence *sequence = node->getSequence();
+ if (sequence->size() >= 1)
+ {
+ TIntermSymbol *sym = sequence->front()->getAsSymbolNode();
+ // Prune declarations without a variable name, unless it's an interface block declaration.
+ if (sym != nullptr && sym->getSymbol() == "" && !sym->isInterfaceBlock())
+ {
+ if (sequence->size() > 1)
+ {
+ // Generate a replacement that will remove the empty declarator in the beginning of a declarator
+ // list. Example of a declaration that will be changed:
+ // float, a;
+ // will be changed to
+ // float a;
+ // This applies also to struct declarations.
+ TIntermSequence emptyReplacement;
+ mMultiReplacements.push_back(NodeReplaceWithMultipleEntry(node, sym, emptyReplacement));
+ }
+ else if (sym->getBasicType() != EbtStruct)
+ {
+ // Single struct declarations may just declare the struct type and no variables, so they should
+ // not be pruned. All other single empty declarations can be pruned entirely. Example of an empty
+ // declaration that will be pruned:
+ // float;
+ TIntermSequence emptyReplacement;
+ TIntermAggregate *parentAgg = getParentNode()->getAsAggregate();
+ ASSERT(parentAgg != nullptr);
+ mMultiReplacements.push_back(NodeReplaceWithMultipleEntry(parentAgg, node, emptyReplacement));
+ }
+ }
+ }
+ return false;
+ }
+ return true;
+}
+
+} // namespace
+
+void PruneEmptyDeclarations(TIntermNode *root)
+{
+ PruneEmptyDeclarationsTraverser::apply(root);
+}
diff --git a/src/3rdparty/angle/src/compiler/translator/PruneEmptyDeclarations.h b/src/3rdparty/angle/src/compiler/translator/PruneEmptyDeclarations.h
new file mode 100644
index 0000000000..122e830902
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/translator/PruneEmptyDeclarations.h
@@ -0,0 +1,15 @@
+//
+// 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 PruneEmptyDeclarations function prunes unnecessary empty declarations and declarators from the AST.
+
+#ifndef COMPILER_TRANSLATOR_PRUNEEMPTYDECLARATIONS_H_
+#define COMPILER_TRANSLATOR_PRUNEEMPTYDECLARATIONS_H_
+
+class TIntermNode;
+
+void PruneEmptyDeclarations(TIntermNode *root);
+
+#endif // COMPILER_TRANSLATOR_PRUNEEMPTYDECLARATIONS_H_
diff --git a/src/3rdparty/angle/src/compiler/translator/RecordConstantPrecision.cpp b/src/3rdparty/angle/src/compiler/translator/RecordConstantPrecision.cpp
new file mode 100644
index 0000000000..14e88b749a
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/translator/RecordConstantPrecision.cpp
@@ -0,0 +1,157 @@
+//
+// Copyright (c) 2002-2015 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// During parsing, all constant expressions are folded to constant union nodes. The expressions that have been
+// folded may have had precision qualifiers, which should affect the precision of the consuming operation.
+// If the folded constant union nodes are written to output as such they won't have any precision qualifiers,
+// and their effect on the precision of the consuming operation is lost.
+//
+// RecordConstantPrecision is an AST traverser that inspects the precision qualifiers of constants and hoists
+// the constants outside the containing expression as precision qualified named variables in case that is
+// required for correct precision propagation.
+//
+
+#include "compiler/translator/RecordConstantPrecision.h"
+
+#include "compiler/translator/InfoSink.h"
+#include "compiler/translator/IntermNode.h"
+
+namespace
+{
+
+class RecordConstantPrecisionTraverser : public TIntermTraverser
+{
+ public:
+ RecordConstantPrecisionTraverser();
+
+ void visitConstantUnion(TIntermConstantUnion *node) override;
+
+ void nextIteration();
+
+ bool foundHigherPrecisionConstant() const { return mFoundHigherPrecisionConstant; }
+ protected:
+ bool operandAffectsParentOperationPrecision(TIntermTyped *operand);
+
+ bool mFoundHigherPrecisionConstant;
+};
+
+RecordConstantPrecisionTraverser::RecordConstantPrecisionTraverser()
+ : TIntermTraverser(true, false, true),
+ mFoundHigherPrecisionConstant(false)
+{
+}
+
+bool RecordConstantPrecisionTraverser::operandAffectsParentOperationPrecision(TIntermTyped *operand)
+{
+ const TIntermBinary *parentAsBinary = getParentNode()->getAsBinaryNode();
+ if (parentAsBinary != nullptr)
+ {
+ // If the constant is assigned or is used to initialize a variable, or if it's an index,
+ // its precision has no effect.
+ switch (parentAsBinary->getOp())
+ {
+ case EOpInitialize:
+ case EOpAssign:
+ case EOpIndexDirect:
+ case EOpIndexDirectStruct:
+ case EOpIndexDirectInterfaceBlock:
+ case EOpIndexIndirect:
+ return false;
+ default:
+ break;
+ }
+
+ TIntermTyped *otherOperand = parentAsBinary->getRight();
+ if (otherOperand == operand)
+ {
+ otherOperand = parentAsBinary->getLeft();
+ }
+ // If the precision of the other child is at least as high as the precision of the constant, the precision of
+ // the constant has no effect.
+ if (otherOperand->getAsConstantUnion() == nullptr && otherOperand->getPrecision() >= operand->getPrecision())
+ {
+ return false;
+ }
+ }
+
+ TIntermAggregate *parentAsAggregate = getParentNode()->getAsAggregate();
+ if (parentAsAggregate != nullptr)
+ {
+ if (!parentAsAggregate->gotPrecisionFromChildren())
+ {
+ // This can be either:
+ // * a call to an user-defined function
+ // * a call to a texture function
+ // * some other kind of aggregate
+ // In any of these cases the constant precision has no effect.
+ return false;
+ }
+ if (parentAsAggregate->isConstructor() && parentAsAggregate->getBasicType() == EbtBool)
+ {
+ return false;
+ }
+ // If the precision of operands does affect the result, but the precision of any of the other children
+ // has a precision that's at least as high as the precision of the constant, the precision of the constant
+ // has no effect.
+ TIntermSequence *parameters = parentAsAggregate->getSequence();
+ for (TIntermNode *parameter : *parameters)
+ {
+ const TIntermTyped *typedParameter = parameter->getAsTyped();
+ if (parameter != operand && typedParameter != nullptr && parameter->getAsConstantUnion() == nullptr &&
+ typedParameter->getPrecision() >= operand->getPrecision())
+ {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+void RecordConstantPrecisionTraverser::visitConstantUnion(TIntermConstantUnion *node)
+{
+ if (mFoundHigherPrecisionConstant)
+ return;
+
+ // If the constant has lowp or undefined precision, it can't increase the precision of consuming operations.
+ if (node->getPrecision() < EbpMedium)
+ return;
+
+ // It's possible the node has no effect on the precision of the consuming expression, depending on the
+ // consuming expression, and the precision of the other parameters of the expression.
+ if (!operandAffectsParentOperationPrecision(node))
+ return;
+
+ // Make the constant a precision-qualified named variable to make sure it affects the precision of the consuming
+ // expression.
+ TIntermSequence insertions;
+ insertions.push_back(createTempInitDeclaration(node, EvqConst));
+ insertStatementsInParentBlock(insertions);
+ mReplacements.push_back(NodeUpdateEntry(getParentNode(), node, createTempSymbol(node->getType()), false));
+ mFoundHigherPrecisionConstant = true;
+}
+
+void RecordConstantPrecisionTraverser::nextIteration()
+{
+ nextTemporaryIndex();
+ mFoundHigherPrecisionConstant = false;
+}
+
+} // namespace
+
+void RecordConstantPrecision(TIntermNode *root, unsigned int *temporaryIndex)
+{
+ RecordConstantPrecisionTraverser traverser;
+ ASSERT(temporaryIndex != nullptr);
+ traverser.useTemporaryIndex(temporaryIndex);
+ // Iterate as necessary, and reset the traverser between iterations.
+ do
+ {
+ traverser.nextIteration();
+ root->traverse(&traverser);
+ if (traverser.foundHigherPrecisionConstant())
+ traverser.updateTree();
+ }
+ while (traverser.foundHigherPrecisionConstant());
+}
diff --git a/src/3rdparty/angle/src/compiler/translator/RecordConstantPrecision.h b/src/3rdparty/angle/src/compiler/translator/RecordConstantPrecision.h
new file mode 100644
index 0000000000..2cd401b418
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/translator/RecordConstantPrecision.h
@@ -0,0 +1,23 @@
+//
+// 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.
+//
+// During parsing, all constant expressions are folded to constant union nodes. The expressions that have been
+// folded may have had precision qualifiers, which should affect the precision of the consuming operation.
+// If the folded constant union nodes are written to output as such they won't have any precision qualifiers,
+// and their effect on the precision of the consuming operation is lost.
+//
+// RecordConstantPrecision is an AST traverser that inspects the precision qualifiers of constants and hoists
+// the constants outside the containing expression as precision qualified named variables in case that is
+// required for correct precision propagation.
+//
+
+#ifndef COMPILER_TRANSLATOR_RECORDCONSTANTPRECISION_H_
+#define COMPILER_TRANSLATOR_RECORDCONSTANTPRECISION_H_
+
+class TIntermNode;
+
+void RecordConstantPrecision(TIntermNode *root, unsigned int *temporaryIndex);
+
+#endif // COMPILER_TRANSLATOR_RECORDCONSTANTPRECISION_H_
diff --git a/src/3rdparty/angle/src/compiler/translator/RegenerateStructNames.cpp b/src/3rdparty/angle/src/compiler/translator/RegenerateStructNames.cpp
index 767b18085c..5e0db2ad26 100644
--- a/src/3rdparty/angle/src/compiler/translator/RegenerateStructNames.cpp
+++ b/src/3rdparty/angle/src/compiler/translator/RegenerateStructNames.cpp
@@ -4,8 +4,8 @@
// found in the LICENSE file.
//
+#include "common/debug.h"
#include "compiler/translator/RegenerateStructNames.h"
-#include "compiler/translator/compilerdebug.h"
void RegenerateStructNames::visitSymbol(TIntermSymbol *symbol)
{
diff --git a/src/3rdparty/angle/src/compiler/translator/RegenerateStructNames.h b/src/3rdparty/angle/src/compiler/translator/RegenerateStructNames.h
index 2acd68be34..3b98e5d709 100644
--- a/src/3rdparty/angle/src/compiler/translator/RegenerateStructNames.h
+++ b/src/3rdparty/angle/src/compiler/translator/RegenerateStructNames.h
@@ -17,13 +17,14 @@ class RegenerateStructNames : public TIntermTraverser
public:
RegenerateStructNames(const TSymbolTable &symbolTable,
int shaderVersion)
- : mSymbolTable(symbolTable),
+ : TIntermTraverser(true, false, false),
+ mSymbolTable(symbolTable),
mShaderVersion(shaderVersion),
mScopeDepth(0) {}
protected:
- virtual void visitSymbol(TIntermSymbol *);
- virtual bool visitAggregate(Visit, TIntermAggregate *);
+ void visitSymbol(TIntermSymbol *) override;
+ bool visitAggregate(Visit, TIntermAggregate *) override;
private:
const TSymbolTable &mSymbolTable;
diff --git a/src/3rdparty/angle/src/compiler/translator/RemoveDynamicIndexing.cpp b/src/3rdparty/angle/src/compiler/translator/RemoveDynamicIndexing.cpp
new file mode 100644
index 0000000000..74814f22a7
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/translator/RemoveDynamicIndexing.cpp
@@ -0,0 +1,513 @@
+//
+// 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.
+//
+// RemoveDynamicIndexing is an AST traverser to remove dynamic indexing of vectors and matrices,
+// replacing them with calls to functions that choose which component to return or write.
+//
+
+#include "compiler/translator/RemoveDynamicIndexing.h"
+
+#include "compiler/translator/InfoSink.h"
+#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/SymbolTable.h"
+
+namespace
+{
+
+TName GetIndexFunctionName(const TType &type, bool write)
+{
+ TInfoSinkBase nameSink;
+ nameSink << "dyn_index_";
+ if (write)
+ {
+ nameSink << "write_";
+ }
+ if (type.isMatrix())
+ {
+ nameSink << "mat" << type.getCols() << "x" << type.getRows();
+ }
+ else
+ {
+ switch (type.getBasicType())
+ {
+ case EbtInt:
+ nameSink << "ivec";
+ break;
+ case EbtBool:
+ nameSink << "bvec";
+ break;
+ case EbtUInt:
+ nameSink << "uvec";
+ break;
+ case EbtFloat:
+ nameSink << "vec";
+ break;
+ default:
+ UNREACHABLE();
+ }
+ nameSink << type.getNominalSize();
+ }
+ TString nameString = TFunction::mangleName(nameSink.c_str());
+ TName name(nameString);
+ name.setInternal(true);
+ return name;
+}
+
+TIntermSymbol *CreateBaseSymbol(const TType &type, TQualifier qualifier)
+{
+ TIntermSymbol *symbol = new TIntermSymbol(0, "base", type);
+ symbol->setInternal(true);
+ symbol->getTypePointer()->setQualifier(qualifier);
+ return symbol;
+}
+
+TIntermSymbol *CreateIndexSymbol()
+{
+ TIntermSymbol *symbol = new TIntermSymbol(0, "index", TType(EbtInt, EbpHigh));
+ symbol->setInternal(true);
+ symbol->getTypePointer()->setQualifier(EvqIn);
+ return symbol;
+}
+
+TIntermSymbol *CreateValueSymbol(const TType &type)
+{
+ TIntermSymbol *symbol = new TIntermSymbol(0, "value", type);
+ symbol->setInternal(true);
+ symbol->getTypePointer()->setQualifier(EvqIn);
+ return symbol;
+}
+
+TIntermConstantUnion *CreateIntConstantNode(int i)
+{
+ TConstantUnion *constant = new TConstantUnion();
+ constant->setIConst(i);
+ return new TIntermConstantUnion(constant, TType(EbtInt, EbpHigh));
+}
+
+TIntermBinary *CreateIndexDirectBaseSymbolNode(const TType &indexedType,
+ const TType &fieldType,
+ const int index,
+ TQualifier baseQualifier)
+{
+ TIntermBinary *indexNode = new TIntermBinary(EOpIndexDirect);
+ indexNode->setType(fieldType);
+ TIntermSymbol *baseSymbol = CreateBaseSymbol(indexedType, baseQualifier);
+ indexNode->setLeft(baseSymbol);
+ indexNode->setRight(CreateIntConstantNode(index));
+ return indexNode;
+}
+
+TIntermBinary *CreateAssignValueSymbolNode(TIntermTyped *targetNode, const TType &assignedValueType)
+{
+ TIntermBinary *assignNode = new TIntermBinary(EOpAssign);
+ assignNode->setType(assignedValueType);
+ assignNode->setLeft(targetNode);
+ assignNode->setRight(CreateValueSymbol(assignedValueType));
+ return assignNode;
+}
+
+TIntermTyped *EnsureSignedInt(TIntermTyped *node)
+{
+ if (node->getBasicType() == EbtInt)
+ return node;
+
+ TIntermAggregate *convertedNode = new TIntermAggregate(EOpConstructInt);
+ convertedNode->setType(TType(EbtInt));
+ convertedNode->getSequence()->push_back(node);
+ convertedNode->setPrecisionFromChildren();
+ return convertedNode;
+}
+
+TType GetFieldType(const TType &indexedType)
+{
+ if (indexedType.isMatrix())
+ {
+ TType fieldType = TType(indexedType.getBasicType(), indexedType.getPrecision());
+ fieldType.setPrimarySize(static_cast<unsigned char>(indexedType.getRows()));
+ return fieldType;
+ }
+ else
+ {
+ return TType(indexedType.getBasicType(), indexedType.getPrecision());
+ }
+}
+
+// Generate a read or write function for one field in a vector/matrix.
+// Out-of-range indices are clamped. This is consistent with how ANGLE handles out-of-range
+// indices in other places.
+// Note that indices can be either int or uint. We create only int versions of the functions,
+// and convert uint indices to int at the call site.
+// read function example:
+// float dyn_index_vec2(in vec2 base, in int index)
+// {
+// switch(index)
+// {
+// case (0):
+// return base[0];
+// case (1):
+// return base[1];
+// default:
+// break;
+// }
+// if (index < 0)
+// return base[0];
+// return base[1];
+// }
+// write function example:
+// void dyn_index_write_vec2(inout vec2 base, in int index, in float value)
+// {
+// switch(index)
+// {
+// case (0):
+// base[0] = value;
+// return;
+// case (1):
+// base[1] = value;
+// return;
+// default:
+// break;
+// }
+// if (index < 0)
+// {
+// base[0] = value;
+// return;
+// }
+// base[1] = value;
+// }
+// Note that else is not used in above functions to avoid the RewriteElseBlocks transformation.
+TIntermAggregate *GetIndexFunctionDefinition(TType type, bool write)
+{
+ ASSERT(!type.isArray());
+ // Conservatively use highp here, even if the indexed type is not highp. That way the code can't
+ // end up using mediump version of an indexing function for a highp value, if both mediump and
+ // highp values are being indexed in the shader. For HLSL precision doesn't matter, but in
+ // principle this code could be used with multiple backends.
+ type.setPrecision(EbpHigh);
+ TIntermAggregate *indexingFunction = new TIntermAggregate(EOpFunction);
+ indexingFunction->setNameObj(GetIndexFunctionName(type, write));
+
+ TType fieldType = GetFieldType(type);
+ int numCases = 0;
+ if (type.isMatrix())
+ {
+ numCases = type.getCols();
+ }
+ else
+ {
+ numCases = type.getNominalSize();
+ }
+ if (write)
+ {
+ indexingFunction->setType(TType(EbtVoid));
+ }
+ else
+ {
+ indexingFunction->setType(fieldType);
+ }
+
+ TIntermAggregate *paramsNode = new TIntermAggregate(EOpParameters);
+ TQualifier baseQualifier = EvqInOut;
+ if (!write)
+ baseQualifier = EvqIn;
+ TIntermSymbol *baseParam = CreateBaseSymbol(type, baseQualifier);
+ paramsNode->getSequence()->push_back(baseParam);
+ TIntermSymbol *indexParam = CreateIndexSymbol();
+ paramsNode->getSequence()->push_back(indexParam);
+ if (write)
+ {
+ TIntermSymbol *valueParam = CreateValueSymbol(fieldType);
+ paramsNode->getSequence()->push_back(valueParam);
+ }
+ indexingFunction->getSequence()->push_back(paramsNode);
+
+ TIntermAggregate *statementList = new TIntermAggregate(EOpSequence);
+ for (int i = 0; i < numCases; ++i)
+ {
+ TIntermCase *caseNode = new TIntermCase(CreateIntConstantNode(i));
+ statementList->getSequence()->push_back(caseNode);
+
+ TIntermBinary *indexNode =
+ CreateIndexDirectBaseSymbolNode(type, fieldType, i, baseQualifier);
+ if (write)
+ {
+ TIntermBinary *assignNode = CreateAssignValueSymbolNode(indexNode, fieldType);
+ statementList->getSequence()->push_back(assignNode);
+ TIntermBranch *returnNode = new TIntermBranch(EOpReturn, nullptr);
+ statementList->getSequence()->push_back(returnNode);
+ }
+ else
+ {
+ TIntermBranch *returnNode = new TIntermBranch(EOpReturn, indexNode);
+ statementList->getSequence()->push_back(returnNode);
+ }
+ }
+
+ // Default case
+ TIntermCase *defaultNode = new TIntermCase(nullptr);
+ statementList->getSequence()->push_back(defaultNode);
+ TIntermBranch *breakNode = new TIntermBranch(EOpBreak, nullptr);
+ statementList->getSequence()->push_back(breakNode);
+
+ TIntermSwitch *switchNode = new TIntermSwitch(CreateIndexSymbol(), statementList);
+
+ TIntermAggregate *bodyNode = new TIntermAggregate(EOpSequence);
+ bodyNode->getSequence()->push_back(switchNode);
+
+ TIntermBinary *cond = new TIntermBinary(EOpLessThan);
+ cond->setType(TType(EbtBool, EbpUndefined));
+ cond->setLeft(CreateIndexSymbol());
+ cond->setRight(CreateIntConstantNode(0));
+
+ // Two blocks: one accesses (either reads or writes) the first element and returns,
+ // the other accesses the last element.
+ TIntermAggregate *useFirstBlock = new TIntermAggregate(EOpSequence);
+ TIntermAggregate *useLastBlock = new TIntermAggregate(EOpSequence);
+ TIntermBinary *indexFirstNode =
+ CreateIndexDirectBaseSymbolNode(type, fieldType, 0, baseQualifier);
+ TIntermBinary *indexLastNode =
+ CreateIndexDirectBaseSymbolNode(type, fieldType, numCases - 1, baseQualifier);
+ if (write)
+ {
+ TIntermBinary *assignFirstNode = CreateAssignValueSymbolNode(indexFirstNode, fieldType);
+ useFirstBlock->getSequence()->push_back(assignFirstNode);
+ TIntermBranch *returnNode = new TIntermBranch(EOpReturn, nullptr);
+ useFirstBlock->getSequence()->push_back(returnNode);
+
+ TIntermBinary *assignLastNode = CreateAssignValueSymbolNode(indexLastNode, fieldType);
+ useLastBlock->getSequence()->push_back(assignLastNode);
+ }
+ else
+ {
+ TIntermBranch *returnFirstNode = new TIntermBranch(EOpReturn, indexFirstNode);
+ useFirstBlock->getSequence()->push_back(returnFirstNode);
+
+ TIntermBranch *returnLastNode = new TIntermBranch(EOpReturn, indexLastNode);
+ useLastBlock->getSequence()->push_back(returnLastNode);
+ }
+ TIntermSelection *ifNode = new TIntermSelection(cond, useFirstBlock, nullptr);
+ bodyNode->getSequence()->push_back(ifNode);
+ bodyNode->getSequence()->push_back(useLastBlock);
+
+ indexingFunction->getSequence()->push_back(bodyNode);
+
+ return indexingFunction;
+}
+
+class RemoveDynamicIndexingTraverser : public TLValueTrackingTraverser
+{
+ public:
+ RemoveDynamicIndexingTraverser(const TSymbolTable &symbolTable, int shaderVersion);
+
+ bool visitBinary(Visit visit, TIntermBinary *node) override;
+
+ void insertHelperDefinitions(TIntermNode *root);
+
+ void nextIteration();
+
+ bool usedTreeInsertion() const { return mUsedTreeInsertion; }
+
+ protected:
+ // Sets of types that are indexed. Note that these can not store multiple variants
+ // of the same type with different precisions - only one precision gets stored.
+ std::set<TType> mIndexedVecAndMatrixTypes;
+ std::set<TType> mWrittenVecAndMatrixTypes;
+
+ bool mUsedTreeInsertion;
+
+ // When true, the traverser will remove side effects from any indexing expression.
+ // This is done so that in code like
+ // V[j++][i]++.
+ // where V is an array of vectors, j++ will only be evaluated once.
+ bool mRemoveIndexSideEffectsInSubtree;
+};
+
+RemoveDynamicIndexingTraverser::RemoveDynamicIndexingTraverser(const TSymbolTable &symbolTable,
+ int shaderVersion)
+ : TLValueTrackingTraverser(true, false, false, symbolTable, shaderVersion),
+ mUsedTreeInsertion(false),
+ mRemoveIndexSideEffectsInSubtree(false)
+{
+}
+
+void RemoveDynamicIndexingTraverser::insertHelperDefinitions(TIntermNode *root)
+{
+ TIntermAggregate *rootAgg = root->getAsAggregate();
+ ASSERT(rootAgg != nullptr && rootAgg->getOp() == EOpSequence);
+ TIntermSequence insertions;
+ for (TType type : mIndexedVecAndMatrixTypes)
+ {
+ insertions.push_back(GetIndexFunctionDefinition(type, false));
+ }
+ for (TType type : mWrittenVecAndMatrixTypes)
+ {
+ insertions.push_back(GetIndexFunctionDefinition(type, true));
+ }
+ mInsertions.push_back(NodeInsertMultipleEntry(rootAgg, 0, insertions, TIntermSequence()));
+}
+
+// Create a call to dyn_index_*() based on an indirect indexing op node
+TIntermAggregate *CreateIndexFunctionCall(TIntermBinary *node,
+ TIntermTyped *indexedNode,
+ TIntermTyped *index)
+{
+ ASSERT(node->getOp() == EOpIndexIndirect);
+ TIntermAggregate *indexingCall = new TIntermAggregate(EOpFunctionCall);
+ indexingCall->setLine(node->getLine());
+ indexingCall->setUserDefined();
+ indexingCall->setNameObj(GetIndexFunctionName(indexedNode->getType(), false));
+ indexingCall->getSequence()->push_back(indexedNode);
+ indexingCall->getSequence()->push_back(index);
+
+ TType fieldType = GetFieldType(indexedNode->getType());
+ indexingCall->setType(fieldType);
+ return indexingCall;
+}
+
+TIntermAggregate *CreateIndexedWriteFunctionCall(TIntermBinary *node,
+ TIntermTyped *index,
+ TIntermTyped *writtenValue)
+{
+ // Deep copy the left node so that two pointers to the same node don't end up in the tree.
+ TIntermNode *leftCopy = node->getLeft()->deepCopy();
+ ASSERT(leftCopy != nullptr && leftCopy->getAsTyped() != nullptr);
+ TIntermAggregate *indexedWriteCall =
+ CreateIndexFunctionCall(node, leftCopy->getAsTyped(), index);
+ indexedWriteCall->setNameObj(GetIndexFunctionName(node->getLeft()->getType(), true));
+ indexedWriteCall->setType(TType(EbtVoid));
+ indexedWriteCall->getSequence()->push_back(writtenValue);
+ return indexedWriteCall;
+}
+
+bool RemoveDynamicIndexingTraverser::visitBinary(Visit visit, TIntermBinary *node)
+{
+ if (mUsedTreeInsertion)
+ return false;
+
+ if (node->getOp() == EOpIndexIndirect)
+ {
+ if (mRemoveIndexSideEffectsInSubtree)
+ {
+ ASSERT(node->getRight()->hasSideEffects());
+ // In case we're just removing index side effects, convert
+ // v_expr[index_expr]
+ // to this:
+ // int s0 = index_expr; v_expr[s0];
+ // Now v_expr[s0] can be safely executed several times without unintended side effects.
+
+ // Init the temp variable holding the index
+ TIntermAggregate *initIndex = createTempInitDeclaration(node->getRight());
+ TIntermSequence insertions;
+ insertions.push_back(initIndex);
+ insertStatementsInParentBlock(insertions);
+ mUsedTreeInsertion = true;
+
+ // Replace the index with the temp variable
+ TIntermSymbol *tempIndex = createTempSymbol(node->getRight()->getType());
+ NodeUpdateEntry replaceIndex(node, node->getRight(), tempIndex, false);
+ mReplacements.push_back(replaceIndex);
+ }
+ else if (!node->getLeft()->isArray() && node->getLeft()->getBasicType() != EbtStruct)
+ {
+ bool write = isLValueRequiredHere();
+
+ TType type = node->getLeft()->getType();
+ mIndexedVecAndMatrixTypes.insert(type);
+
+ if (write)
+ {
+ // Convert:
+ // v_expr[index_expr]++;
+ // to this:
+ // int s0 = index_expr; float s1 = dyn_index(v_expr, s0); s1++;
+ // dyn_index_write(v_expr, s0, s1);
+ // This works even if index_expr has some side effects.
+ if (node->getLeft()->hasSideEffects())
+ {
+ // If v_expr has side effects, those need to be removed before proceeding.
+ // Otherwise the side effects of v_expr would be evaluated twice.
+ // The only case where an l-value can have side effects is when it is
+ // indexing. For example, it can be V[j++] where V is an array of vectors.
+ mRemoveIndexSideEffectsInSubtree = true;
+ return true;
+ }
+ // TODO(oetuaho@nvidia.com): This is not optimal if the expression using the value
+ // only writes it and doesn't need the previous value. http://anglebug.com/1116
+
+ mWrittenVecAndMatrixTypes.insert(type);
+ TType fieldType = GetFieldType(type);
+
+ TIntermSequence insertionsBefore;
+ TIntermSequence insertionsAfter;
+
+ // Store the index in a temporary signed int variable.
+ TIntermTyped *indexInitializer = EnsureSignedInt(node->getRight());
+ TIntermAggregate *initIndex = createTempInitDeclaration(indexInitializer);
+ initIndex->setLine(node->getLine());
+ insertionsBefore.push_back(initIndex);
+
+ TIntermAggregate *indexingCall = CreateIndexFunctionCall(
+ node, node->getLeft(), createTempSymbol(indexInitializer->getType()));
+
+ // Create a node for referring to the index after the nextTemporaryIndex() call
+ // below.
+ TIntermSymbol *tempIndex = createTempSymbol(indexInitializer->getType());
+
+ nextTemporaryIndex(); // From now on, creating temporary symbols that refer to the
+ // field value.
+ insertionsBefore.push_back(createTempInitDeclaration(indexingCall));
+
+ TIntermAggregate *indexedWriteCall =
+ CreateIndexedWriteFunctionCall(node, tempIndex, createTempSymbol(fieldType));
+ insertionsAfter.push_back(indexedWriteCall);
+ insertStatementsInParentBlock(insertionsBefore, insertionsAfter);
+ NodeUpdateEntry replaceIndex(getParentNode(), node, createTempSymbol(fieldType),
+ false);
+ mReplacements.push_back(replaceIndex);
+ mUsedTreeInsertion = true;
+ }
+ else
+ {
+ // The indexed value is not being written, so we can simply convert
+ // v_expr[index_expr]
+ // into
+ // dyn_index(v_expr, index_expr)
+ // If the index_expr is unsigned, we'll convert it to signed.
+ ASSERT(!mRemoveIndexSideEffectsInSubtree);
+ TIntermAggregate *indexingCall = CreateIndexFunctionCall(
+ node, node->getLeft(), EnsureSignedInt(node->getRight()));
+ NodeUpdateEntry replaceIndex(getParentNode(), node, indexingCall, false);
+ mReplacements.push_back(replaceIndex);
+ }
+ }
+ }
+ return !mUsedTreeInsertion;
+}
+
+void RemoveDynamicIndexingTraverser::nextIteration()
+{
+ mUsedTreeInsertion = false;
+ mRemoveIndexSideEffectsInSubtree = false;
+ nextTemporaryIndex();
+}
+
+} // namespace
+
+void RemoveDynamicIndexing(TIntermNode *root,
+ unsigned int *temporaryIndex,
+ const TSymbolTable &symbolTable,
+ int shaderVersion)
+{
+ RemoveDynamicIndexingTraverser traverser(symbolTable, shaderVersion);
+ ASSERT(temporaryIndex != nullptr);
+ traverser.useTemporaryIndex(temporaryIndex);
+ do
+ {
+ traverser.nextIteration();
+ root->traverse(&traverser);
+ traverser.updateTree();
+ } while (traverser.usedTreeInsertion());
+ traverser.insertHelperDefinitions(root);
+ traverser.updateTree();
+}
diff --git a/src/3rdparty/angle/src/compiler/translator/RemoveDynamicIndexing.h b/src/3rdparty/angle/src/compiler/translator/RemoveDynamicIndexing.h
new file mode 100644
index 0000000000..ae3a93c9b1
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/translator/RemoveDynamicIndexing.h
@@ -0,0 +1,21 @@
+//
+// 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.
+//
+// RemoveDynamicIndexing is an AST traverser to remove dynamic indexing of vectors and matrices,
+// replacing them with calls to functions that choose which component to return or write.
+//
+
+#ifndef COMPILER_TRANSLATOR_REMOVEDYNAMICINDEXING_H_
+#define COMPILER_TRANSLATOR_REMOVEDYNAMICINDEXING_H_
+
+class TIntermNode;
+class TSymbolTable;
+
+void RemoveDynamicIndexing(TIntermNode *root,
+ unsigned int *temporaryIndex,
+ const TSymbolTable &symbolTable,
+ int shaderVersion);
+
+#endif // COMPILER_TRANSLATOR_REMOVEDYNAMICINDEXING_H_
diff --git a/src/3rdparty/angle/src/compiler/translator/RemovePow.cpp b/src/3rdparty/angle/src/compiler/translator/RemovePow.cpp
new file mode 100644
index 0000000000..6dbb48da9c
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/translator/RemovePow.cpp
@@ -0,0 +1,105 @@
+//
+// 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.
+//
+// RemovePow is an AST traverser to convert pow(x, y) built-in calls where y is a
+// constant to exp2(y * log2(x)). This works around an issue in NVIDIA 311 series
+// OpenGL drivers.
+//
+
+#include "compiler/translator/RemovePow.h"
+
+#include "compiler/translator/InfoSink.h"
+#include "compiler/translator/IntermNode.h"
+
+namespace
+{
+
+bool IsProblematicPow(TIntermTyped *node)
+{
+ TIntermAggregate *agg = node->getAsAggregate();
+ if (agg != nullptr && agg->getOp() == EOpPow)
+ {
+ ASSERT(agg->getSequence()->size() == 2);
+ return agg->getSequence()->at(1)->getAsConstantUnion() != nullptr;
+ }
+ return false;
+}
+
+// Traverser that converts all pow operations simultaneously.
+class RemovePowTraverser : public TIntermTraverser
+{
+ public:
+ RemovePowTraverser();
+
+ bool visitAggregate(Visit visit, TIntermAggregate *node) override;
+
+ void nextIteration() { mNeedAnotherIteration = false; }
+ bool needAnotherIteration() const { return mNeedAnotherIteration; }
+
+ protected:
+ bool mNeedAnotherIteration;
+};
+
+RemovePowTraverser::RemovePowTraverser()
+ : TIntermTraverser(true, false, false),
+ mNeedAnotherIteration(false)
+{
+}
+
+bool RemovePowTraverser::visitAggregate(Visit visit, TIntermAggregate *node)
+{
+ if (IsProblematicPow(node))
+ {
+ TInfoSink nullSink;
+
+ TIntermTyped *x = node->getSequence()->at(0)->getAsTyped();
+ TIntermTyped *y = node->getSequence()->at(1)->getAsTyped();
+
+ TIntermUnary *log = new TIntermUnary(EOpLog2);
+ log->setOperand(x);
+ log->setLine(node->getLine());
+ log->setType(x->getType());
+
+ TIntermBinary *mul = new TIntermBinary(EOpMul);
+ mul->setLeft(y);
+ mul->setRight(log);
+ mul->setLine(node->getLine());
+ bool valid = mul->promote(nullSink);
+ UNUSED_ASSERTION_VARIABLE(valid);
+ ASSERT(valid);
+
+ TIntermUnary *exp = new TIntermUnary(EOpExp2);
+ exp->setOperand(mul);
+ exp->setLine(node->getLine());
+ exp->setType(node->getType());
+
+ NodeUpdateEntry replacePow(getParentNode(), node, exp, false);
+ mReplacements.push_back(replacePow);
+
+ // If the x parameter also needs to be replaced, we need to do that in another traversal,
+ // since it's parent node will change in a way that's not handled correctly by updateTree().
+ if (IsProblematicPow(x))
+ {
+ mNeedAnotherIteration = true;
+ return false;
+ }
+ }
+ return true;
+}
+
+} // namespace
+
+void RemovePow(TIntermNode *root)
+{
+ RemovePowTraverser traverser;
+ // Iterate as necessary, and reset the traverser between iterations.
+ do
+ {
+ traverser.nextIteration();
+ root->traverse(&traverser);
+ traverser.updateTree();
+ }
+ while (traverser.needAnotherIteration());
+}
diff --git a/src/3rdparty/angle/src/compiler/translator/RemovePow.h b/src/3rdparty/angle/src/compiler/translator/RemovePow.h
new file mode 100644
index 0000000000..40f9d672b2
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/translator/RemovePow.h
@@ -0,0 +1,18 @@
+//
+// 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.
+//
+// RemovePow is an AST traverser to convert pow(x, y) built-in calls where y is a
+// constant to exp2(y * log2(x)). This works around an issue in NVIDIA 311 series
+// OpenGL drivers.
+//
+
+#ifndef COMPILER_TRANSLATOR_REMOVEPOW_H_
+#define COMPILER_TRANSLATOR_REMOVEPOW_H_
+
+class TIntermNode;
+
+void RemovePow(TIntermNode *root);
+
+#endif // COMPILER_TRANSLATOR_REMOVEPOW_H_
diff --git a/src/3rdparty/angle/src/compiler/translator/RenameFunction.h b/src/3rdparty/angle/src/compiler/translator/RenameFunction.h
index 868e5d566b..fd6a365fea 100644
--- a/src/3rdparty/angle/src/compiler/translator/RenameFunction.h
+++ b/src/3rdparty/angle/src/compiler/translator/RenameFunction.h
@@ -20,7 +20,7 @@ public:
, mOldFunctionName(oldFunctionName)
, mNewFunctionName(newFunctionName) {}
- virtual bool visitAggregate(Visit visit, TIntermAggregate* node)
+ bool visitAggregate(Visit visit, TIntermAggregate *node) override
{
TOperator op = node->getOp();
if ((op == EOpFunction || op == EOpFunctionCall) && node->getName() == mOldFunctionName)
diff --git a/src/3rdparty/angle/src/compiler/translator/RewriteDoWhile.cpp b/src/3rdparty/angle/src/compiler/translator/RewriteDoWhile.cpp
new file mode 100644
index 0000000000..8347447546
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/translator/RewriteDoWhile.cpp
@@ -0,0 +1,163 @@
+//
+// 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.
+//
+
+// RewriteDoWhile.cpp: rewrites do-while loops using another equivalent
+// construct.
+
+#include "compiler/translator/RewriteDoWhile.h"
+
+#include "compiler/translator/IntermNode.h"
+
+namespace
+{
+
+// An AST traverser that rewrites loops of the form
+// do {
+// CODE;
+// } while (CONDITION)
+//
+// to loops of the form
+// bool temp = false;
+// while (true) {
+// if (temp) {
+// if (!CONDITION) {
+// break;
+// }
+// }
+// temp = true;
+// CODE;
+// }
+//
+// The reason we don't use a simpler form, with for example just (temp && !CONDITION) in the
+// while condition, is that short-circuit is often badly supported by driver shader compiler.
+// The double if has the same effect, but forces shader compilers to behave.
+//
+// TODO(cwallez) when UnfoldShortCircuitIntoIf handles loops correctly, revisit this as we might
+// be able to use while (temp || CONDITION) with temp initially set to true then run
+// UnfoldShortCircuitIntoIf
+class DoWhileRewriter : public TIntermTraverser
+{
+ public:
+ DoWhileRewriter() : TIntermTraverser(true, false, false) {}
+
+ bool visitAggregate(Visit, TIntermAggregate *node) override
+ {
+ // A well-formed AST can only have do-while in EOpSequence which represent lists of
+ // statements. By doing a prefix traversal we are able to replace the do-while in the
+ // sequence directly as the content of the do-while will be traversed later.
+ if (node->getOp() != EOpSequence)
+ {
+ return true;
+ }
+
+ TIntermSequence *statements = node->getSequence();
+
+ // The statements vector will have new statements inserted when we encounter a do-while,
+ // which prevents us from using a range-based for loop. Using the usual i++ works, as
+ // the (two) new statements inserted replace the statement at the current position.
+ for (size_t i = 0; i < statements->size(); i++)
+ {
+ TIntermNode *statement = (*statements)[i];
+ TIntermLoop *loop = statement->getAsLoopNode();
+
+ if (loop == nullptr || loop->getType() != ELoopDoWhile)
+ {
+ continue;
+ }
+
+ TType boolType = TType(EbtBool);
+
+ // bool temp = false;
+ TIntermAggregate *tempDeclaration = nullptr;
+ {
+ TConstantUnion *falseConstant = new TConstantUnion();
+ falseConstant->setBConst(false);
+ TIntermTyped *falseValue = new TIntermConstantUnion(falseConstant, boolType);
+
+ tempDeclaration = createTempInitDeclaration(falseValue);
+ }
+
+ // temp = true;
+ TIntermBinary *assignTrue = nullptr;
+ {
+ TConstantUnion *trueConstant = new TConstantUnion();
+ trueConstant->setBConst(true);
+ TIntermTyped *trueValue = new TIntermConstantUnion(trueConstant, boolType);
+
+ assignTrue = createTempAssignment(trueValue);
+ }
+
+ // if (temp) {
+ // if (!CONDITION) {
+ // break;
+ // }
+ // }
+ TIntermSelection *breakIf = nullptr;
+ {
+ TIntermBranch *breakStatement = new TIntermBranch(EOpBreak, nullptr);
+
+ TIntermAggregate *breakBlock = new TIntermAggregate(EOpSequence);
+ breakBlock->getSequence()->push_back(breakStatement);
+
+ TIntermUnary *negatedCondition = new TIntermUnary(EOpLogicalNot);
+ negatedCondition->setOperand(loop->getCondition());
+
+ TIntermSelection *innerIf =
+ new TIntermSelection(negatedCondition, breakBlock, nullptr);
+
+ TIntermAggregate *innerIfBlock = new TIntermAggregate(EOpSequence);
+ innerIfBlock->getSequence()->push_back(innerIf);
+
+ breakIf = new TIntermSelection(createTempSymbol(boolType), innerIfBlock, nullptr);
+ }
+
+ // Assemble the replacement loops, reusing the do-while loop's body and inserting our
+ // statements at the front.
+ TIntermLoop *newLoop = nullptr;
+ {
+ TConstantUnion *trueConstant = new TConstantUnion();
+ trueConstant->setBConst(true);
+ TIntermTyped *trueValue = new TIntermConstantUnion(trueConstant, boolType);
+
+ TIntermAggregate *body = nullptr;
+ if (loop->getBody() != nullptr)
+ {
+ body = loop->getBody()->getAsAggregate();
+ }
+ else
+ {
+ body = new TIntermAggregate(EOpSequence);
+ }
+ auto sequence = body->getSequence();
+ sequence->insert(sequence->begin(), assignTrue);
+ sequence->insert(sequence->begin(), breakIf);
+
+ newLoop = new TIntermLoop(ELoopWhile, nullptr, trueValue, nullptr, body);
+ }
+
+ TIntermSequence replacement;
+ replacement.push_back(tempDeclaration);
+ replacement.push_back(newLoop);
+
+ node->replaceChildNodeWithMultiple(loop, replacement);
+
+ nextTemporaryIndex();
+ }
+ return true;
+ }
+};
+
+} // anonymous namespace
+
+void RewriteDoWhile(TIntermNode *root, unsigned int *temporaryIndex)
+{
+ ASSERT(temporaryIndex != 0);
+
+ DoWhileRewriter rewriter;
+ rewriter.useTemporaryIndex(temporaryIndex);
+
+ root->traverse(&rewriter);
+}
diff --git a/src/3rdparty/angle/src/compiler/translator/RewriteDoWhile.h b/src/3rdparty/angle/src/compiler/translator/RewriteDoWhile.h
new file mode 100644
index 0000000000..f6ec1caf06
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/translator/RewriteDoWhile.h
@@ -0,0 +1,16 @@
+//
+// 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.
+//
+
+// RewriteDoWhile.h: rewrite do-while loops as while loops to work around
+// driver bugs
+
+#ifndef COMPILER_TRANSLATOR_REWRITEDOWHILE_H_
+#define COMPILER_TRANSLATOR_REWRITEDOWHILE_H_
+
+class TIntermNode;
+void RewriteDoWhile(TIntermNode *root, unsigned int *temporaryIndex);
+
+#endif // COMPILER_TRANSLATOR_REWRITEDOWHILE_H_
diff --git a/src/3rdparty/angle/src/compiler/translator/RewriteElseBlocks.cpp b/src/3rdparty/angle/src/compiler/translator/RewriteElseBlocks.cpp
index b03beb5c6c..52ede17434 100644
--- a/src/3rdparty/angle/src/compiler/translator/RewriteElseBlocks.cpp
+++ b/src/3rdparty/angle/src/compiler/translator/RewriteElseBlocks.cpp
@@ -23,30 +23,14 @@ class ElseBlockRewriter : public TIntermTraverser
ElseBlockRewriter();
protected:
- bool visitAggregate(Visit visit, TIntermAggregate *aggregate);
+ bool visitAggregate(Visit visit, TIntermAggregate *aggregate) override;
private:
- int mTemporaryIndex;
const TType *mFunctionType;
TIntermNode *rewriteSelection(TIntermSelection *selection);
};
-TIntermSymbol *MakeNewTemporary(const TString &name, TBasicType type)
-{
- TType variableType(type, EbpHigh, EvqInternal);
- return new TIntermSymbol(-1, name, variableType);
-}
-
-TIntermBinary *MakeNewBinary(TOperator op, TIntermTyped *left, TIntermTyped *right, const TType &resultType)
-{
- TIntermBinary *binary = new TIntermBinary(op);
- binary->setLeft(left);
- binary->setRight(right);
- binary->setType(resultType);
- return binary;
-}
-
TIntermUnary *MakeNewUnary(TOperator op, TIntermTyped *operand)
{
TIntermUnary *unary = new TIntermUnary(op, operand->getType());
@@ -55,8 +39,7 @@ TIntermUnary *MakeNewUnary(TOperator op, TIntermTyped *operand)
}
ElseBlockRewriter::ElseBlockRewriter()
- : TIntermTraverser(true, false, true, false),
- mTemporaryIndex(0),
+ : TIntermTraverser(true, false, true),
mFunctionType(NULL)
{}
@@ -71,7 +54,7 @@ bool ElseBlockRewriter::visitAggregate(Visit visit, TIntermAggregate *node)
{
TIntermNode *statement = (*node->getSequence())[statementIndex];
TIntermSelection *selection = statement->getAsSelectionNode();
- if (selection && selection->getFalseBlock() != NULL)
+ if (selection && selection->getFalseBlock() != nullptr)
{
// Check for if / else if
TIntermSelection *elseIfBranch = selection->getFalseBlock()->getAsSelectionNode();
@@ -101,20 +84,20 @@ bool ElseBlockRewriter::visitAggregate(Visit visit, TIntermAggregate *node)
TIntermNode *ElseBlockRewriter::rewriteSelection(TIntermSelection *selection)
{
- ASSERT(selection != NULL);
+ ASSERT(selection != nullptr);
+
+ nextTemporaryIndex();
- TString temporaryName = "cond_" + str(mTemporaryIndex++);
TIntermTyped *typedCondition = selection->getCondition()->getAsTyped();
- TType resultType(EbtBool, EbpUndefined);
- TIntermSymbol *conditionSymbolInit = MakeNewTemporary(temporaryName, EbtBool);
- TIntermBinary *storeCondition = MakeNewBinary(EOpInitialize, conditionSymbolInit,
- typedCondition, resultType);
- TIntermNode *negatedElse = NULL;
+ TIntermAggregate *storeCondition = createTempInitDeclaration(typedCondition);
- TIntermSelection *falseBlock = NULL;
+ TIntermSelection *falseBlock = nullptr;
+
+ TType boolType(EbtBool, EbpUndefined, EvqTemporary);
if (selection->getFalseBlock())
{
+ TIntermAggregate *negatedElse = nullptr;
// crbug.com/346463
// D3D generates error messages claiming a function has no return value, when rewriting
// an if-else clause that returns something non-void in a function. By appending dummy
@@ -124,24 +107,22 @@ TIntermNode *ElseBlockRewriter::rewriteSelection(TIntermSelection *selection)
TString typeString = mFunctionType->getStruct() ? mFunctionType->getStruct()->name() :
mFunctionType->getBasicString();
TString rawText = "return (" + typeString + ")0";
- negatedElse = new TIntermRaw(*mFunctionType, rawText);
+ TIntermRaw *returnNode = new TIntermRaw(*mFunctionType, rawText);
+ negatedElse = new TIntermAggregate(EOpSequence);
+ negatedElse->getSequence()->push_back(returnNode);
}
- TIntermSymbol *conditionSymbolElse = MakeNewTemporary(temporaryName, EbtBool);
+ TIntermSymbol *conditionSymbolElse = createTempSymbol(boolType);
TIntermUnary *negatedCondition = MakeNewUnary(EOpLogicalNot, conditionSymbolElse);
falseBlock = new TIntermSelection(negatedCondition,
selection->getFalseBlock(), negatedElse);
}
- TIntermSymbol *conditionSymbolSel = MakeNewTemporary(temporaryName, EbtBool);
- TIntermSelection *newSelection = new TIntermSelection(conditionSymbolSel,
- selection->getTrueBlock(), falseBlock);
-
- TIntermAggregate *declaration = new TIntermAggregate(EOpDeclaration);
- declaration->getSequence()->push_back(storeCondition);
+ TIntermSymbol *conditionSymbolSel = createTempSymbol(boolType);
+ TIntermSelection *newSelection = new TIntermSelection(conditionSymbolSel, selection->getTrueBlock(), falseBlock);
TIntermAggregate *block = new TIntermAggregate(EOpSequence);
- block->getSequence()->push_back(declaration);
+ block->getSequence()->push_back(storeCondition);
block->getSequence()->push_back(newSelection);
return block;
@@ -149,9 +130,10 @@ TIntermNode *ElseBlockRewriter::rewriteSelection(TIntermSelection *selection)
}
-void RewriteElseBlocks(TIntermNode *node)
+void RewriteElseBlocks(TIntermNode *node, unsigned int *temporaryIndex)
{
ElseBlockRewriter rewriter;
+ rewriter.useTemporaryIndex(temporaryIndex);
node->traverse(&rewriter);
}
diff --git a/src/3rdparty/angle/src/compiler/translator/RewriteElseBlocks.h b/src/3rdparty/angle/src/compiler/translator/RewriteElseBlocks.h
index 5527d27f83..24a425e66d 100644
--- a/src/3rdparty/angle/src/compiler/translator/RewriteElseBlocks.h
+++ b/src/3rdparty/angle/src/compiler/translator/RewriteElseBlocks.h
@@ -15,7 +15,7 @@
namespace sh
{
-void RewriteElseBlocks(TIntermNode *node);
+void RewriteElseBlocks(TIntermNode *node, unsigned int *temporaryIndex);
}
diff --git a/src/3rdparty/angle/src/compiler/translator/ScalarizeVecAndMatConstructorArgs.cpp b/src/3rdparty/angle/src/compiler/translator/ScalarizeVecAndMatConstructorArgs.cpp
index 8857ad59bd..775c5d8710 100644
--- a/src/3rdparty/angle/src/compiler/translator/ScalarizeVecAndMatConstructorArgs.cpp
+++ b/src/3rdparty/angle/src/compiler/translator/ScalarizeVecAndMatConstructorArgs.cpp
@@ -4,8 +4,8 @@
// found in the LICENSE file.
//
+#include "common/debug.h"
#include "compiler/translator/ScalarizeVecAndMatConstructorArgs.h"
-#include "compiler/translator/compilerdebug.h"
#include <algorithm>
@@ -39,7 +39,7 @@ bool ContainsVectorNode(const TIntermSequence &sequence)
TIntermConstantUnion *ConstructIndexNode(int index)
{
- ConstantUnion *u = new ConstantUnion[1];
+ TConstantUnion *u = new TConstantUnion[1];
u[0].setIConst(index);
TType type(EbtInt, EbpUndefined, EvqConst, 1);
@@ -109,7 +109,13 @@ bool ScalarizeVecAndMatConstructorArgs::visitAggregate(Visit visit, TIntermAggre
scalarizeArgs(node, false, true);
break;
case EOpConstructMat2:
+ case EOpConstructMat2x3:
+ case EOpConstructMat2x4:
+ case EOpConstructMat3x2:
case EOpConstructMat3:
+ case EOpConstructMat3x4:
+ case EOpConstructMat4x2:
+ case EOpConstructMat4x3:
case EOpConstructMat4:
if (ContainsVectorNode(*(node->getSequence())))
scalarizeArgs(node, true, false);
@@ -144,9 +150,21 @@ void ScalarizeVecAndMatConstructorArgs::scalarizeArgs(
case EOpConstructMat2:
size = 4;
break;
+ case EOpConstructMat2x3:
+ case EOpConstructMat3x2:
+ size = 6;
+ break;
+ case EOpConstructMat2x4:
+ case EOpConstructMat4x2:
+ size = 8;
+ break;
case EOpConstructMat3:
size = 9;
break;
+ case EOpConstructMat3x4:
+ case EOpConstructMat4x3:
+ size = 12;
+ break;
case EOpConstructMat4:
size = 16;
break;
diff --git a/src/3rdparty/angle/src/compiler/translator/ScalarizeVecAndMatConstructorArgs.h b/src/3rdparty/angle/src/compiler/translator/ScalarizeVecAndMatConstructorArgs.h
index 0726ed4c64..d7553be23b 100644
--- a/src/3rdparty/angle/src/compiler/translator/ScalarizeVecAndMatConstructorArgs.h
+++ b/src/3rdparty/angle/src/compiler/translator/ScalarizeVecAndMatConstructorArgs.h
@@ -14,12 +14,13 @@ class ScalarizeVecAndMatConstructorArgs : public TIntermTraverser
public:
ScalarizeVecAndMatConstructorArgs(sh::GLenum shaderType,
bool fragmentPrecisionHigh)
- : mTempVarCount(0),
+ : TIntermTraverser(true, false, false),
+ mTempVarCount(0),
mShaderType(shaderType),
mFragmentPrecisionHigh(fragmentPrecisionHigh) {}
protected:
- virtual bool visitAggregate(Visit visit, TIntermAggregate *node);
+ bool visitAggregate(Visit visit, TIntermAggregate *node) override;
private:
void scalarizeArgs(TIntermAggregate *aggregate,
diff --git a/src/3rdparty/angle/src/compiler/translator/SearchSymbol.cpp b/src/3rdparty/angle/src/compiler/translator/SearchSymbol.cpp
index fb7a6cdb9b..cccd4d3ff0 100644
--- a/src/3rdparty/angle/src/compiler/translator/SearchSymbol.cpp
+++ b/src/3rdparty/angle/src/compiler/translator/SearchSymbol.cpp
@@ -12,7 +12,9 @@
namespace sh
{
-SearchSymbol::SearchSymbol(const TString &symbol) : mSymbol(symbol)
+SearchSymbol::SearchSymbol(const TString &symbol)
+ : TIntermTraverser(true, false, false),
+ mSymbol(symbol)
{
match = false;
}
diff --git a/src/3rdparty/angle/src/compiler/translator/SearchSymbol.h b/src/3rdparty/angle/src/compiler/translator/SearchSymbol.h
index 36d5191058..1e5e1700d1 100644
--- a/src/3rdparty/angle/src/compiler/translator/SearchSymbol.h
+++ b/src/3rdparty/angle/src/compiler/translator/SearchSymbol.h
@@ -20,7 +20,7 @@ class SearchSymbol : public TIntermTraverser
SearchSymbol(const TString &symbol);
void traverse(TIntermNode *node);
- void visitSymbol(TIntermSymbol *symbolNode);
+ void visitSymbol(TIntermSymbol *symbolNode) override;
bool foundMatch() const;
diff --git a/src/3rdparty/angle/src/compiler/translator/SeparateArrayInitialization.cpp b/src/3rdparty/angle/src/compiler/translator/SeparateArrayInitialization.cpp
new file mode 100644
index 0000000000..de9050cd80
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/translator/SeparateArrayInitialization.cpp
@@ -0,0 +1,92 @@
+//
+// 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 SeparateArrayInitialization function splits each array initialization into a declaration and an assignment.
+// Example:
+// type[n] a = initializer;
+// will effectively become
+// type[n] a;
+// a = initializer;
+//
+// Note that if the array is declared as const, the initialization may still be split, making the
+// AST technically invalid. Because of that this transformation should only be used when subsequent
+// stages don't care about const qualifiers. However, the initialization will not be split if the
+// initializer can be written as a HLSL literal.
+
+#include "compiler/translator/SeparateArrayInitialization.h"
+
+#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/OutputHLSL.h"
+
+namespace
+{
+
+class SeparateArrayInitTraverser : private TIntermTraverser
+{
+ public:
+ static void apply(TIntermNode *root);
+ private:
+ SeparateArrayInitTraverser();
+ bool visitAggregate(Visit, TIntermAggregate *node) override;
+};
+
+void SeparateArrayInitTraverser::apply(TIntermNode *root)
+{
+ SeparateArrayInitTraverser separateInit;
+ root->traverse(&separateInit);
+ separateInit.updateTree();
+}
+
+SeparateArrayInitTraverser::SeparateArrayInitTraverser()
+ : TIntermTraverser(true, false, false)
+{
+}
+
+bool SeparateArrayInitTraverser::visitAggregate(Visit, TIntermAggregate *node)
+{
+ if (node->getOp() == EOpDeclaration)
+ {
+ TIntermSequence *sequence = node->getSequence();
+ TIntermBinary *initNode = sequence->back()->getAsBinaryNode();
+ if (initNode != nullptr && initNode->getOp() == EOpInitialize)
+ {
+ TIntermTyped *initializer = initNode->getRight();
+ if (initializer->isArray() && !sh::OutputHLSL::canWriteAsHLSLLiteral(initializer))
+ {
+ // We rely on that array declarations have been isolated to single declarations.
+ ASSERT(sequence->size() == 1);
+ TIntermTyped *symbol = initNode->getLeft();
+ TIntermAggregate *parentAgg = getParentNode()->getAsAggregate();
+ ASSERT(parentAgg != nullptr);
+
+ TIntermSequence replacements;
+
+ TIntermAggregate *replacementDeclaration = new TIntermAggregate;
+ replacementDeclaration->setOp(EOpDeclaration);
+ replacementDeclaration->getSequence()->push_back(symbol);
+ replacementDeclaration->setLine(symbol->getLine());
+ replacements.push_back(replacementDeclaration);
+
+ TIntermBinary *replacementAssignment = new TIntermBinary(EOpAssign);
+ replacementAssignment->setLeft(symbol);
+ replacementAssignment->setRight(initializer);
+ replacementAssignment->setType(initializer->getType());
+ replacementAssignment->setLine(symbol->getLine());
+ replacements.push_back(replacementAssignment);
+
+ mMultiReplacements.push_back(NodeReplaceWithMultipleEntry(parentAgg, node, replacements));
+ }
+ }
+ return false;
+ }
+ return true;
+}
+
+} // namespace
+
+void SeparateArrayInitialization(TIntermNode *root)
+{
+ SeparateArrayInitTraverser::apply(root);
+}
diff --git a/src/3rdparty/angle/src/compiler/translator/SeparateArrayInitialization.h b/src/3rdparty/angle/src/compiler/translator/SeparateArrayInitialization.h
new file mode 100644
index 0000000000..d16357a3af
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/translator/SeparateArrayInitialization.h
@@ -0,0 +1,25 @@
+//
+// Copyright (c) 2002-2015 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// The SeparateArrayInitialization function splits each array initialization into a declaration and an assignment.
+// Example:
+// type[n] a = initializer;
+// will effectively become
+// type[n] a;
+// a = initializer;
+//
+// Note that if the array is declared as const, the initialization may still be split, making the
+// AST technically invalid. Because of that this transformation should only be used when subsequent
+// stages don't care about const qualifiers. However, the initialization will not be split if the
+// initializer can be written as a HLSL literal.
+
+#ifndef COMPILER_TRANSLATOR_SEPARATEARRAYINITIALIZATION_H_
+#define COMPILER_TRANSLATOR_SEPARATEARRAYINITIALIZATION_H_
+
+class TIntermNode;
+
+void SeparateArrayInitialization(TIntermNode *root);
+
+#endif // COMPILER_TRANSLATOR_SEPARATEARRAYINITIALIZATION_H_
diff --git a/src/3rdparty/angle/src/compiler/translator/SeparateDeclarations.cpp b/src/3rdparty/angle/src/compiler/translator/SeparateDeclarations.cpp
new file mode 100644
index 0000000000..d33747f85b
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/translator/SeparateDeclarations.cpp
@@ -0,0 +1,77 @@
+//
+// 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 SeparateDeclarations function processes declarations, so that in the end each declaration
+// contains only one declarator.
+// This is useful as an intermediate step when initialization needs to be separated from declaration,
+// or when things need to be unfolded out of the initializer.
+// Example:
+// int a[1] = int[1](1), b[1] = int[1](2);
+// gets transformed when run through this class into the AST equivalent of:
+// int a[1] = int[1](1);
+// int b[1] = int[1](2);
+
+#include "compiler/translator/SeparateDeclarations.h"
+
+#include "compiler/translator/IntermNode.h"
+
+namespace
+{
+
+class SeparateDeclarationsTraverser : private TIntermTraverser
+{
+ public:
+ static void apply(TIntermNode *root);
+ private:
+ SeparateDeclarationsTraverser();
+ bool visitAggregate(Visit, TIntermAggregate *node) override;
+};
+
+void SeparateDeclarationsTraverser::apply(TIntermNode *root)
+{
+ SeparateDeclarationsTraverser separateDecl;
+ root->traverse(&separateDecl);
+ separateDecl.updateTree();
+}
+
+SeparateDeclarationsTraverser::SeparateDeclarationsTraverser()
+ : TIntermTraverser(true, false, false)
+{
+}
+
+bool SeparateDeclarationsTraverser::visitAggregate(Visit, TIntermAggregate *node)
+{
+ if (node->getOp() == EOpDeclaration)
+ {
+ TIntermSequence *sequence = node->getSequence();
+ if (sequence->size() > 1)
+ {
+ TIntermAggregate *parentAgg = getParentNode()->getAsAggregate();
+ ASSERT(parentAgg != nullptr);
+
+ TIntermSequence replacementDeclarations;
+ for (size_t ii = 0; ii < sequence->size(); ++ii)
+ {
+ TIntermAggregate *replacementDeclaration = new TIntermAggregate;
+
+ replacementDeclaration->setOp(EOpDeclaration);
+ replacementDeclaration->getSequence()->push_back(sequence->at(ii));
+ replacementDeclaration->setLine(sequence->at(ii)->getLine());
+ replacementDeclarations.push_back(replacementDeclaration);
+ }
+
+ mMultiReplacements.push_back(NodeReplaceWithMultipleEntry(parentAgg, node, replacementDeclarations));
+ }
+ return false;
+ }
+ return true;
+}
+
+} // namespace
+
+void SeparateDeclarations(TIntermNode *root)
+{
+ SeparateDeclarationsTraverser::apply(root);
+}
diff --git a/src/3rdparty/angle/src/compiler/translator/SeparateDeclarations.h b/src/3rdparty/angle/src/compiler/translator/SeparateDeclarations.h
new file mode 100644
index 0000000000..77913ab8bb
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/translator/SeparateDeclarations.h
@@ -0,0 +1,23 @@
+//
+// 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 SeparateDeclarations function processes declarations, so that in the end each declaration
+// contains only one declarator.
+// This is useful as an intermediate step when initialization needs to be separated from declaration,
+// or when things need to be unfolded out of the initializer.
+// Example:
+// int a[1] = int[1](1), b[1] = int[1](2);
+// gets transformed when run through this class into the AST equivalent of:
+// int a[1] = int[1](1);
+// int b[1] = int[1](2);
+
+#ifndef COMPILER_TRANSLATOR_SEPARATEDECLARATIONS_H_
+#define COMPILER_TRANSLATOR_SEPARATEDECLARATIONS_H_
+
+class TIntermNode;
+
+void SeparateDeclarations(TIntermNode *root);
+
+#endif // COMPILER_TRANSLATOR_SEPARATEDECLARATIONS_H_
diff --git a/src/3rdparty/angle/src/compiler/translator/SeparateExpressionsReturningArrays.cpp b/src/3rdparty/angle/src/compiler/translator/SeparateExpressionsReturningArrays.cpp
new file mode 100644
index 0000000000..e8e1a21d9c
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/translator/SeparateExpressionsReturningArrays.cpp
@@ -0,0 +1,169 @@
+//
+// 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.
+//
+// SeparateExpressionsReturningArrays splits array-returning expressions that are not array names from more complex
+// expressions, assigning them to a temporary variable a#.
+// Examples where a, b and c are all arrays:
+// (a = b) == (a = c) is split into a = b; type[n] a1 = a; a = c; type[n] a2 = a; a1 == a2;
+// type d = type[n](...)[i]; is split into type[n] a1 = type[n](...); type d = a1[i];
+
+#include "compiler/translator/SeparateExpressionsReturningArrays.h"
+
+#include "compiler/translator/IntermNode.h"
+
+namespace
+{
+
+// Traverser that separates one array expression into a statement at a time.
+class SeparateExpressionsTraverser : public TIntermTraverser
+{
+ public:
+ SeparateExpressionsTraverser();
+
+ bool visitBinary(Visit visit, TIntermBinary *node) override;
+ bool visitAggregate(Visit visit, TIntermAggregate *node) override;
+
+ void nextIteration();
+ bool foundArrayExpression() const { return mFoundArrayExpression; }
+
+ protected:
+ // Marked to true once an operation that needs to be hoisted out of the expression has been found.
+ // After that, no more AST updates are performed on that traversal.
+ bool mFoundArrayExpression;
+};
+
+SeparateExpressionsTraverser::SeparateExpressionsTraverser()
+ : TIntermTraverser(true, false, false),
+ mFoundArrayExpression(false)
+{
+}
+
+// Performs a shallow copy of an assignment node.
+// These shallow copies are useful when a node gets inserted into an aggregate node
+// and also needs to be replaced in its original location by a different node.
+TIntermBinary *CopyAssignmentNode(TIntermBinary *node)
+{
+ TIntermBinary *copyNode = new TIntermBinary(node->getOp());
+ copyNode->setLeft(node->getLeft());
+ copyNode->setRight(node->getRight());
+ copyNode->setType(node->getType());
+ return copyNode;
+}
+
+// Performs a shallow copy of a constructor/function call node.
+TIntermAggregate *CopyAggregateNode(TIntermAggregate *node)
+{
+ TIntermAggregate *copyNode = new TIntermAggregate(node->getOp());
+ TIntermSequence *copySeq = copyNode->getSequence();
+ copySeq->insert(copySeq->begin(), node->getSequence()->begin(), node->getSequence()->end());
+ copyNode->setType(node->getType());
+ copyNode->setFunctionId(node->getFunctionId());
+ if (node->isUserDefined())
+ {
+ copyNode->setUserDefined();
+ }
+ copyNode->setNameObj(node->getNameObj());
+ return copyNode;
+}
+
+bool SeparateExpressionsTraverser::visitBinary(Visit visit, TIntermBinary *node)
+{
+ if (mFoundArrayExpression)
+ return false;
+
+ // Early return if the expression is not an array or if we're not inside a complex expression.
+ if (!node->getType().isArray() || parentNodeIsBlock())
+ return true;
+
+ switch (node->getOp())
+ {
+ case EOpAssign:
+ {
+ mFoundArrayExpression = true;
+
+ TIntermSequence insertions;
+ insertions.push_back(CopyAssignmentNode(node));
+ // TODO(oetuaho): In some cases it would be more optimal to not add the temporary node, but just use the
+ // original target of the assignment. Care must be taken so that this doesn't happen when the same array
+ // symbol is a target of assignment more than once in one expression.
+ insertions.push_back(createTempInitDeclaration(node->getLeft()));
+ insertStatementsInParentBlock(insertions);
+
+ NodeUpdateEntry replaceVariable(getParentNode(), node, createTempSymbol(node->getType()), false);
+ mReplacements.push_back(replaceVariable);
+ }
+ return false;
+ default:
+ return true;
+ }
+}
+
+bool SeparateExpressionsTraverser::visitAggregate(Visit visit, TIntermAggregate *node)
+{
+ if (mFoundArrayExpression)
+ return false; // No need to traverse further
+
+ if (getParentNode() != nullptr)
+ {
+ TIntermBinary *parentBinary = getParentNode()->getAsBinaryNode();
+ bool parentIsAssignment = (parentBinary != nullptr &&
+ (parentBinary->getOp() == EOpAssign || parentBinary->getOp() == EOpInitialize));
+
+ if (!node->getType().isArray() || parentNodeIsBlock() || parentIsAssignment)
+ return true;
+
+ if (node->isConstructor())
+ {
+ mFoundArrayExpression = true;
+
+ TIntermSequence insertions;
+ insertions.push_back(createTempInitDeclaration(CopyAggregateNode(node)));
+ insertStatementsInParentBlock(insertions);
+
+ NodeUpdateEntry replaceVariable(getParentNode(), node, createTempSymbol(node->getType()), false);
+ mReplacements.push_back(replaceVariable);
+
+ return false;
+ }
+ else if (node->getOp() == EOpFunctionCall)
+ {
+ mFoundArrayExpression = true;
+
+ TIntermSequence insertions;
+ insertions.push_back(createTempInitDeclaration(CopyAggregateNode(node)));
+ insertStatementsInParentBlock(insertions);
+
+ NodeUpdateEntry replaceVariable(getParentNode(), node, createTempSymbol(node->getType()), false);
+ mReplacements.push_back(replaceVariable);
+
+ return false;
+ }
+ }
+ return true;
+}
+
+void SeparateExpressionsTraverser::nextIteration()
+{
+ mFoundArrayExpression = false;
+ nextTemporaryIndex();
+}
+
+} // namespace
+
+void SeparateExpressionsReturningArrays(TIntermNode *root, unsigned int *temporaryIndex)
+{
+ SeparateExpressionsTraverser traverser;
+ ASSERT(temporaryIndex != nullptr);
+ traverser.useTemporaryIndex(temporaryIndex);
+ // Separate one expression at a time, and reset the traverser between iterations.
+ do
+ {
+ traverser.nextIteration();
+ root->traverse(&traverser);
+ if (traverser.foundArrayExpression())
+ traverser.updateTree();
+ }
+ while (traverser.foundArrayExpression());
+}
diff --git a/src/3rdparty/angle/src/compiler/translator/SeparateExpressionsReturningArrays.h b/src/3rdparty/angle/src/compiler/translator/SeparateExpressionsReturningArrays.h
new file mode 100644
index 0000000000..b178ebb3ec
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/translator/SeparateExpressionsReturningArrays.h
@@ -0,0 +1,19 @@
+//
+// 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.
+//
+// SeparateExpressionsReturningArrays splits array-returning expressions that are not array names from more complex
+// expressions, assigning them to a temporary variable a#.
+// Examples where a, b and c are all arrays:
+// (a = b) == (a = c) is split into a = b; type[n] a1 = a; a = c; type[n] a2 = a; a1 == a2;
+// type d = type[n](...)[i]; is split into type[n] a1 = type[n](...); type d = a1[i];
+
+#ifndef COMPILER_TRANSLATOR_SEPARATEEXPRESSIONSRETURNINGARRAYS_H_
+#define COMPILER_TRANSLATOR_SEPARATEEXPRESSIONSRETURNINGARRAYS_H_
+
+class TIntermNode;
+
+void SeparateExpressionsReturningArrays(TIntermNode *root, unsigned int *temporaryIndex);
+
+#endif // COMPILER_TRANSLATOR_SEPARATEEXPRESSIONSRETURNINGARRAYS_H_
diff --git a/src/3rdparty/angle/src/compiler/translator/ShaderLang.cpp b/src/3rdparty/angle/src/compiler/translator/ShaderLang.cpp
index b8040da7f9..e257f93e48 100644
--- a/src/3rdparty/angle/src/compiler/translator/ShaderLang.cpp
+++ b/src/3rdparty/angle/src/compiler/translator/ShaderLang.cpp
@@ -23,15 +23,6 @@
namespace
{
-enum ShaderVariableType
-{
- SHADERVAR_UNIFORM,
- SHADERVAR_VARYING,
- SHADERVAR_ATTRIBUTE,
- SHADERVAR_OUTPUTVARIABLE,
- SHADERVAR_INTERFACEBLOCK
-};
-
bool isInitialized = false;
//
@@ -40,36 +31,40 @@ bool isInitialized = false;
//
template <typename VarT>
-const std::vector<VarT> *GetVariableList(const TCompiler *compiler, ShaderVariableType variableType);
+const std::vector<VarT> *GetVariableList(const TCompiler *compiler);
template <>
-const std::vector<sh::Uniform> *GetVariableList(const TCompiler *compiler, ShaderVariableType)
+const std::vector<sh::Uniform> *GetVariableList(const TCompiler *compiler)
{
return &compiler->getUniforms();
}
template <>
-const std::vector<sh::Varying> *GetVariableList(const TCompiler *compiler, ShaderVariableType)
+const std::vector<sh::Varying> *GetVariableList(const TCompiler *compiler)
{
return &compiler->getVaryings();
}
template <>
-const std::vector<sh::Attribute> *GetVariableList(const TCompiler *compiler, ShaderVariableType variableType)
+const std::vector<sh::Attribute> *GetVariableList(const TCompiler *compiler)
+{
+ return &compiler->getAttributes();
+}
+
+template <>
+const std::vector<sh::OutputVariable> *GetVariableList(const TCompiler *compiler)
{
- return (variableType == SHADERVAR_ATTRIBUTE ?
- &compiler->getAttributes() :
- &compiler->getOutputVariables());
+ return &compiler->getOutputVariables();
}
template <>
-const std::vector<sh::InterfaceBlock> *GetVariableList(const TCompiler *compiler, ShaderVariableType)
+const std::vector<sh::InterfaceBlock> *GetVariableList(const TCompiler *compiler)
{
return &compiler->getInterfaceBlocks();
}
template <typename VarT>
-const std::vector<VarT> *GetShaderVariables(const ShHandle handle, ShaderVariableType variableType)
+const std::vector<VarT> *GetShaderVariables(const ShHandle handle)
{
if (!handle)
{
@@ -83,7 +78,7 @@ const std::vector<VarT> *GetShaderVariables(const ShHandle handle, ShaderVariabl
return NULL;
}
- return GetVariableList<VarT>(compiler, variableType);
+ return GetVariableList<VarT>(compiler);
}
TCompiler *GetCompilerFromHandle(ShHandle handle)
@@ -104,7 +99,7 @@ TranslatorHLSL *GetTranslatorHLSLFromHandle(ShHandle handle)
}
#endif // ANGLE_ENABLE_HLSL
-} // namespace anonymous
+} // anonymous namespace
//
// Driver must call this first, once, before doing any other compiler operations.
@@ -154,6 +149,7 @@ void ShInitBuiltInResources(ShBuiltInResources* resources)
resources->OES_standard_derivatives = 0;
resources->OES_EGL_image_external = 0;
resources->ARB_texture_rectangle = 0;
+ resources->EXT_blend_func_extended = 0;
resources->EXT_draw_buffers = 0;
resources->EXT_frag_depth = 0;
resources->EXT_shader_texture_lod = 0;
@@ -173,6 +169,9 @@ void ShInitBuiltInResources(ShBuiltInResources* resources)
resources->MinProgramTexelOffset = -8;
resources->MaxProgramTexelOffset = 7;
+ // Extensions constants.
+ resources->MaxDualSourceDrawBuffers = 0;
+
// Disable name hashing by default.
resources->HashFunction = NULL;
@@ -190,9 +189,16 @@ ShHandle ShConstructCompiler(sh::GLenum type, ShShaderSpec spec,
const ShBuiltInResources* resources)
{
TShHandleBase* base = static_cast<TShHandleBase*>(ConstructCompiler(type, spec, output));
+ if (base == nullptr)
+ {
+ return 0;
+ }
+
TCompiler* compiler = base->getAsCompiler();
- if (compiler == 0)
+ if (compiler == nullptr)
+ {
return 0;
+ }
// Generate built-in symbol table.
if (!compiler->Init(*resources)) {
@@ -240,6 +246,13 @@ bool ShCompile(
return compiler->compile(shaderStrings, numStrings, compileOptions);
}
+void ShClearResults(const ShHandle handle)
+{
+ TCompiler *compiler = GetCompilerFromHandle(handle);
+ ASSERT(compiler);
+ compiler->clearResults();
+}
+
int ShGetShaderVersion(const ShHandle handle)
{
TCompiler* compiler = GetCompilerFromHandle(handle);
@@ -288,27 +301,27 @@ const std::map<std::string, std::string> *ShGetNameHashingMap(
const std::vector<sh::Uniform> *ShGetUniforms(const ShHandle handle)
{
- return GetShaderVariables<sh::Uniform>(handle, SHADERVAR_UNIFORM);
+ return GetShaderVariables<sh::Uniform>(handle);
}
const std::vector<sh::Varying> *ShGetVaryings(const ShHandle handle)
{
- return GetShaderVariables<sh::Varying>(handle, SHADERVAR_VARYING);
+ return GetShaderVariables<sh::Varying>(handle);
}
const std::vector<sh::Attribute> *ShGetAttributes(const ShHandle handle)
{
- return GetShaderVariables<sh::Attribute>(handle, SHADERVAR_ATTRIBUTE);
+ return GetShaderVariables<sh::Attribute>(handle);
}
-const std::vector<sh::Attribute> *ShGetOutputVariables(const ShHandle handle)
+const std::vector<sh::OutputVariable> *ShGetOutputVariables(const ShHandle handle)
{
- return GetShaderVariables<sh::Attribute>(handle, SHADERVAR_OUTPUTVARIABLE);
+ return GetShaderVariables<sh::OutputVariable>(handle);
}
const std::vector<sh::InterfaceBlock> *ShGetInterfaceBlocks(const ShHandle handle)
{
- return GetShaderVariables<sh::InterfaceBlock>(handle, SHADERVAR_INTERFACEBLOCK);
+ return GetShaderVariables<sh::InterfaceBlock>(handle);
}
bool ShCheckVariablesWithinPackingLimits(
diff --git a/src/3rdparty/angle/src/compiler/translator/ShaderVars.cpp b/src/3rdparty/angle/src/compiler/translator/ShaderVars.cpp
index 0dbbc9e7f6..8f931b9bdd 100644
--- a/src/3rdparty/angle/src/compiler/translator/ShaderVars.cpp
+++ b/src/3rdparty/angle/src/compiler/translator/ShaderVars.cpp
@@ -9,7 +9,7 @@
#include <GLSLANG/ShaderLang.h>
-#include "compiler/translator/compilerdebug.h"
+#include "common/debug.h"
namespace sh
{
@@ -217,31 +217,75 @@ bool Uniform::isSameUniformAtLinkTime(const Uniform &other) const
return ShaderVariable::isSameVariableAtLinkTime(other, true);
}
-Attribute::Attribute()
- : location(-1)
+InterfaceVariable::InterfaceVariable() : location(-1)
{}
-Attribute::~Attribute()
+InterfaceVariable::~InterfaceVariable()
{}
-Attribute::Attribute(const Attribute &other)
- : ShaderVariable(other),
- location(other.location)
+InterfaceVariable::InterfaceVariable(const InterfaceVariable &other)
+ : ShaderVariable(other), location(other.location)
{}
-Attribute &Attribute::operator=(const Attribute &other)
+InterfaceVariable &InterfaceVariable::operator=(const InterfaceVariable &other)
{
ShaderVariable::operator=(other);
location = other.location;
return *this;
}
-bool Attribute::operator==(const Attribute &other) const
+bool InterfaceVariable::operator==(const InterfaceVariable &other) const
{
return (ShaderVariable::operator==(other) &&
location == other.location);
}
+Attribute::Attribute()
+{
+}
+
+Attribute::~Attribute()
+{
+}
+
+Attribute::Attribute(const Attribute &other) : InterfaceVariable(other)
+{
+}
+
+Attribute &Attribute::operator=(const Attribute &other)
+{
+ InterfaceVariable::operator=(other);
+ return *this;
+}
+
+bool Attribute::operator==(const Attribute &other) const
+{
+ return InterfaceVariable::operator==(other);
+}
+
+OutputVariable::OutputVariable()
+{
+}
+
+OutputVariable::~OutputVariable()
+{
+}
+
+OutputVariable::OutputVariable(const OutputVariable &other) : InterfaceVariable(other)
+{
+}
+
+OutputVariable &OutputVariable::operator=(const OutputVariable &other)
+{
+ InterfaceVariable::operator=(other);
+ return *this;
+}
+
+bool OutputVariable::operator==(const OutputVariable &other) const
+{
+ return InterfaceVariable::operator==(other);
+}
+
InterfaceBlockField::InterfaceBlockField()
: isRowMajorLayout(false)
{}
@@ -305,9 +349,14 @@ bool Varying::operator==(const Varying &other) const
bool Varying::isSameVaryingAtLinkTime(const Varying &other) const
{
+ return isSameVaryingAtLinkTime(other, 100);
+}
+
+bool Varying::isSameVaryingAtLinkTime(const Varying &other, int shaderVersion) const
+{
return (ShaderVariable::isSameVariableAtLinkTime(other, false) &&
interpolation == other.interpolation &&
- isInvariant == other.isInvariant);
+ (shaderVersion >= 300 || isInvariant == other.isInvariant));
}
InterfaceBlock::InterfaceBlock()
@@ -344,4 +393,9 @@ InterfaceBlock &InterfaceBlock::operator=(const InterfaceBlock &other)
return *this;
}
+std::string InterfaceBlock::fieldPrefix() const
+{
+ return instanceName.empty() ? "" : name;
}
+
+} // namespace sh
diff --git a/src/3rdparty/angle/src/compiler/translator/SymbolTable.cpp b/src/3rdparty/angle/src/compiler/translator/SymbolTable.cpp
index 0eb663f018..dc8f8e3b6b 100644
--- a/src/3rdparty/angle/src/compiler/translator/SymbolTable.cpp
+++ b/src/3rdparty/angle/src/compiler/translator/SymbolTable.cpp
@@ -14,6 +14,7 @@
#endif
#include "compiler/translator/SymbolTable.h"
+#include "compiler/translator/Cache.h"
#include <stdio.h>
#include <algorithm>
@@ -29,6 +30,18 @@ TFunction::~TFunction()
delete (*i).type;
}
+const TString *TFunction::buildMangledName() const
+{
+ std::string newName = mangleName(getName()).c_str();
+
+ for (const auto &p : parameters)
+ {
+ newName += p.type->getMangledName().c_str();
+ }
+
+ return NewPoolTString(newName.c_str());
+}
+
//
// Symbol table levels are a map of pointers to symbols that have to be deleted.
//
@@ -139,7 +152,7 @@ bool IsVecType(const TType *type)
return false;
}
-TType *SpecificType(TType *type, int size)
+const TType *SpecificType(const TType *type, int size)
{
ASSERT(size >= 1 && size <= 4);
@@ -152,15 +165,15 @@ TType *SpecificType(TType *type, int size)
switch(type->getBasicType())
{
- case EbtGenType: return new TType(EbtFloat, size);
- case EbtGenIType: return new TType(EbtInt, size);
- case EbtGenUType: return new TType(EbtUInt, size);
- case EbtGenBType: return new TType(EbtBool, size);
+ case EbtGenType: return TCache::getType(EbtFloat, static_cast<unsigned char>(size));
+ case EbtGenIType: return TCache::getType(EbtInt, static_cast<unsigned char>(size));
+ case EbtGenUType: return TCache::getType(EbtUInt, static_cast<unsigned char>(size));
+ case EbtGenBType: return TCache::getType(EbtBool, static_cast<unsigned char>(size));
default: return type;
}
}
-TType *VectorType(TType *type, int size)
+const TType *VectorType(const TType *type, int size)
{
ASSERT(size >= 2 && size <= 4);
@@ -173,44 +186,44 @@ TType *VectorType(TType *type, int size)
switch(type->getBasicType())
{
- case EbtVec: return new TType(EbtFloat, size);
- case EbtIVec: return new TType(EbtInt, size);
- case EbtUVec: return new TType(EbtUInt, size);
- case EbtBVec: return new TType(EbtBool, size);
+ case EbtVec: return TCache::getType(EbtFloat, static_cast<unsigned char>(size));
+ case EbtIVec: return TCache::getType(EbtInt, static_cast<unsigned char>(size));
+ case EbtUVec: return TCache::getType(EbtUInt, static_cast<unsigned char>(size));
+ case EbtBVec: return TCache::getType(EbtBool, static_cast<unsigned char>(size));
default: return type;
}
}
-void TSymbolTable::insertBuiltIn(ESymbolLevel level, TOperator op, const char *ext, TType *rvalue, const char *name,
- TType *ptype1, TType *ptype2, TType *ptype3, TType *ptype4, TType *ptype5)
+void TSymbolTable::insertBuiltIn(ESymbolLevel level, TOperator op, const char *ext, const TType *rvalue, const char *name,
+ const TType *ptype1, const TType *ptype2, const TType *ptype3, const TType *ptype4, const TType *ptype5)
{
if (ptype1->getBasicType() == EbtGSampler2D)
{
bool gvec4 = (rvalue->getBasicType() == EbtGVec4);
- insertBuiltIn(level, gvec4 ? new TType(EbtFloat, 4) : rvalue, name, new TType(EbtSampler2D), ptype2, ptype3, ptype4, ptype5);
- insertBuiltIn(level, gvec4 ? new TType(EbtInt, 4) : rvalue, name, new TType(EbtISampler2D), ptype2, ptype3, ptype4, ptype5);
- insertBuiltIn(level, gvec4 ? new TType(EbtUInt, 4) : rvalue, name, new TType(EbtUSampler2D), ptype2, ptype3, ptype4, ptype5);
+ insertBuiltIn(level, gvec4 ? TCache::getType(EbtFloat, 4) : rvalue, name, TCache::getType(EbtSampler2D), ptype2, ptype3, ptype4, ptype5);
+ insertBuiltIn(level, gvec4 ? TCache::getType(EbtInt, 4) : rvalue, name, TCache::getType(EbtISampler2D), ptype2, ptype3, ptype4, ptype5);
+ insertBuiltIn(level, gvec4 ? TCache::getType(EbtUInt, 4) : rvalue, name, TCache::getType(EbtUSampler2D), ptype2, ptype3, ptype4, ptype5);
}
else if (ptype1->getBasicType() == EbtGSampler3D)
{
bool gvec4 = (rvalue->getBasicType() == EbtGVec4);
- insertBuiltIn(level, gvec4 ? new TType(EbtFloat, 4) : rvalue, name, new TType(EbtSampler3D), ptype2, ptype3, ptype4, ptype5);
- insertBuiltIn(level, gvec4 ? new TType(EbtInt, 4) : rvalue, name, new TType(EbtISampler3D), ptype2, ptype3, ptype4, ptype5);
- insertBuiltIn(level, gvec4 ? new TType(EbtUInt, 4) : rvalue, name, new TType(EbtUSampler3D), ptype2, ptype3, ptype4, ptype5);
+ insertBuiltIn(level, gvec4 ? TCache::getType(EbtFloat, 4) : rvalue, name, TCache::getType(EbtSampler3D), ptype2, ptype3, ptype4, ptype5);
+ insertBuiltIn(level, gvec4 ? TCache::getType(EbtInt, 4) : rvalue, name, TCache::getType(EbtISampler3D), ptype2, ptype3, ptype4, ptype5);
+ insertBuiltIn(level, gvec4 ? TCache::getType(EbtUInt, 4) : rvalue, name, TCache::getType(EbtUSampler3D), ptype2, ptype3, ptype4, ptype5);
}
else if (ptype1->getBasicType() == EbtGSamplerCube)
{
bool gvec4 = (rvalue->getBasicType() == EbtGVec4);
- insertBuiltIn(level, gvec4 ? new TType(EbtFloat, 4) : rvalue, name, new TType(EbtSamplerCube), ptype2, ptype3, ptype4, ptype5);
- insertBuiltIn(level, gvec4 ? new TType(EbtInt, 4) : rvalue, name, new TType(EbtISamplerCube), ptype2, ptype3, ptype4, ptype5);
- insertBuiltIn(level, gvec4 ? new TType(EbtUInt, 4) : rvalue, name, new TType(EbtUSamplerCube), ptype2, ptype3, ptype4, ptype5);
+ insertBuiltIn(level, gvec4 ? TCache::getType(EbtFloat, 4) : rvalue, name, TCache::getType(EbtSamplerCube), ptype2, ptype3, ptype4, ptype5);
+ insertBuiltIn(level, gvec4 ? TCache::getType(EbtInt, 4) : rvalue, name, TCache::getType(EbtISamplerCube), ptype2, ptype3, ptype4, ptype5);
+ insertBuiltIn(level, gvec4 ? TCache::getType(EbtUInt, 4) : rvalue, name, TCache::getType(EbtUSamplerCube), ptype2, ptype3, ptype4, ptype5);
}
else if (ptype1->getBasicType() == EbtGSampler2DArray)
{
bool gvec4 = (rvalue->getBasicType() == EbtGVec4);
- insertBuiltIn(level, gvec4 ? new TType(EbtFloat, 4) : rvalue, name, new TType(EbtSampler2DArray), ptype2, ptype3, ptype4, ptype5);
- insertBuiltIn(level, gvec4 ? new TType(EbtInt, 4) : rvalue, name, new TType(EbtISampler2DArray), ptype2, ptype3, ptype4, ptype5);
- insertBuiltIn(level, gvec4 ? new TType(EbtUInt, 4) : rvalue, name, new TType(EbtUSampler2DArray), ptype2, ptype3, ptype4, ptype5);
+ insertBuiltIn(level, gvec4 ? TCache::getType(EbtFloat, 4) : rvalue, name, TCache::getType(EbtSampler2DArray), ptype2, ptype3, ptype4, ptype5);
+ insertBuiltIn(level, gvec4 ? TCache::getType(EbtInt, 4) : rvalue, name, TCache::getType(EbtISampler2DArray), ptype2, ptype3, ptype4, ptype5);
+ insertBuiltIn(level, gvec4 ? TCache::getType(EbtUInt, 4) : rvalue, name, TCache::getType(EbtUSampler2DArray), ptype2, ptype3, ptype4, ptype5);
}
else if (IsGenType(rvalue) || IsGenType(ptype1) || IsGenType(ptype2) || IsGenType(ptype3))
{
@@ -229,33 +242,28 @@ void TSymbolTable::insertBuiltIn(ESymbolLevel level, TOperator op, const char *e
}
else
{
- TFunction *function = new TFunction(NewPoolTString(name), *rvalue, op, ext);
+ TFunction *function = new TFunction(NewPoolTString(name), rvalue, op, ext);
- TParameter param1 = {0, ptype1};
- function->addParameter(param1);
+ function->addParameter(TConstParameter(ptype1));
if (ptype2)
{
- TParameter param2 = {0, ptype2};
- function->addParameter(param2);
+ function->addParameter(TConstParameter(ptype2));
}
if (ptype3)
{
- TParameter param3 = {0, ptype3};
- function->addParameter(param3);
+ function->addParameter(TConstParameter(ptype3));
}
if (ptype4)
{
- TParameter param4 = {0, ptype4};
- function->addParameter(param4);
+ function->addParameter(TConstParameter(ptype4));
}
if (ptype5)
{
- TParameter param5 = {0, ptype5};
- function->addParameter(param5);
+ function->addParameter(TConstParameter(ptype5));
}
insert(level, function);
@@ -272,7 +280,7 @@ TPrecision TSymbolTable::getDefaultPrecision(TBasicType type) const
int level = static_cast<int>(precisionStack.size()) - 1;
assert(level >= 0); // Just to be safe. Should not happen.
- // If we dont find anything we return this. Should we error check this?
+ // If we dont find anything we return this. Some types don't have predefined default precision.
TPrecision prec = EbpUndefined;
while (level >= 0)
{
diff --git a/src/3rdparty/angle/src/compiler/translator/SymbolTable.h b/src/3rdparty/angle/src/compiler/translator/SymbolTable.h
index dfc65cb957..2706149e3c 100644
--- a/src/3rdparty/angle/src/compiler/translator/SymbolTable.h
+++ b/src/3rdparty/angle/src/compiler/translator/SymbolTable.h
@@ -109,13 +109,8 @@ class TVariable : public TSymbol
unionArray(0)
{
}
- virtual ~TVariable()
- {
- }
- virtual bool isVariable() const
- {
- return true;
- }
+ ~TVariable() override {}
+ bool isVariable() const override { return true; }
TType &getType()
{
return type;
@@ -133,40 +128,67 @@ class TVariable : public TSymbol
type.setQualifier(qualifier);
}
- ConstantUnion *getConstPointer()
- {
- if (!unionArray)
- unionArray = new ConstantUnion[type.getObjectSize()];
+ const TConstantUnion *getConstPointer() const { return unionArray; }
- return unionArray;
- }
-
- ConstantUnion *getConstPointer() const
- {
- return unionArray;
- }
-
- void shareConstPointer(ConstantUnion *constArray)
- {
- if (unionArray == constArray)
- return;
-
- delete[] unionArray;
- unionArray = constArray;
- }
+ void shareConstPointer(const TConstantUnion *constArray) { unionArray = constArray; }
private:
TType type;
bool userType;
// we are assuming that Pool Allocator will free the memory
// allocated to unionArray when this object is destroyed.
- ConstantUnion *unionArray;
+ const TConstantUnion *unionArray;
+};
+
+// Immutable version of TParameter.
+struct TConstParameter
+{
+ TConstParameter()
+ : name(nullptr),
+ type(nullptr)
+ {
+ }
+ explicit TConstParameter(const TString *n)
+ : name(n),
+ type(nullptr)
+ {
+ }
+ explicit TConstParameter(const TType *t)
+ : name(nullptr),
+ type(t)
+ {
+ }
+ TConstParameter(const TString *n, const TType *t)
+ : name(n),
+ type(t)
+ {
+ }
+
+ // Both constructor arguments must be const.
+ TConstParameter(TString *n, TType *t) = delete;
+ TConstParameter(const TString *n, TType *t) = delete;
+ TConstParameter(TString *n, const TType *t) = delete;
+
+ const TString *name;
+ const TType *type;
};
// The function sub-class of symbols and the parser will need to
// share this definition of a function parameter.
struct TParameter
{
+ // Destructively converts to TConstParameter.
+ // This method resets name and type to nullptrs to make sure
+ // their content cannot be modified after the call.
+ TConstParameter turnToConst()
+ {
+ const TString *constName = name;
+ const TType *constType = type;
+ name = nullptr;
+ type = nullptr;
+ return TConstParameter(constName, constType);
+ }
+
TString *name;
TType *type;
};
@@ -175,27 +197,21 @@ struct TParameter
class TFunction : public TSymbol
{
public:
- TFunction(TOperator o)
- : TSymbol(0),
- returnType(TType(EbtVoid, EbpUndefined)),
- op(o),
- defined(false)
- {
- }
- TFunction(const TString *name, const TType &retType, TOperator tOp = EOpNull, const char *ext = "")
+ TFunction(const TString *name,
+ const TType *retType,
+ TOperator tOp = EOpNull,
+ const char *ext = "")
: TSymbol(name),
returnType(retType),
- mangledName(TFunction::mangleName(*name)),
+ mangledName(nullptr),
op(tOp),
- defined(false)
+ defined(false),
+ mHasPrototypeDeclaration(false)
{
relateToExtension(ext);
}
- virtual ~TFunction();
- virtual bool isFunction() const
- {
- return true;
- }
+ ~TFunction() override;
+ bool isFunction() const override { return true; }
static TString mangleName(const TString &name)
{
@@ -206,19 +222,23 @@ class TFunction : public TSymbol
return TString(mangledName.c_str(), mangledName.find_first_of('('));
}
- void addParameter(TParameter &p)
- {
+ void addParameter(const TConstParameter &p)
+ {
parameters.push_back(p);
- mangledName = mangledName + p.type->getMangledName();
+ mangledName = nullptr;
}
- const TString &getMangledName() const
+ const TString &getMangledName() const override
{
- return mangledName;
+ if (mangledName == nullptr)
+ {
+ mangledName = buildMangledName();
+ }
+ return *mangledName;
}
const TType &getReturnType() const
{
- return returnType;
+ return *returnType;
}
TOperator getBuiltInOp() const
@@ -226,31 +246,30 @@ class TFunction : public TSymbol
return op;
}
- void setDefined()
- {
- defined = true;
- }
- bool isDefined()
- {
- return defined;
- }
+ void setDefined() { defined = true; }
+ bool isDefined() { return defined; }
+ void setHasPrototypeDeclaration() { mHasPrototypeDeclaration = true; }
+ bool hasPrototypeDeclaration() const { return mHasPrototypeDeclaration; }
size_t getParamCount() const
{
return parameters.size();
}
- const TParameter &getParam(size_t i) const
+ const TConstParameter &getParam(size_t i) const
{
return parameters[i];
}
private:
- typedef TVector<TParameter> TParamList;
+ const TString *buildMangledName() const;
+
+ typedef TVector<TConstParameter> TParamList;
TParamList parameters;
- TType returnType;
- TString mangledName;
+ const TType *returnType;
+ mutable const TString *mangledName;
TOperator op;
bool defined;
+ bool mHasPrototypeDeclaration;
};
// Interface block name sub-symbol
@@ -364,27 +383,39 @@ class TSymbolTable : angle::NonCopyable
{
TVariable *constant = new TVariable(
NewPoolTString(name), TType(EbtInt, EbpUndefined, EvqConst, 1));
- constant->getConstPointer()->setIConst(value);
+ TConstantUnion *unionArray = new TConstantUnion[1];
+ unionArray[0].setIConst(value);
+ constant->shareConstPointer(unionArray);
return insert(level, constant);
}
- void insertBuiltIn(ESymbolLevel level, TOperator op, const char *ext, TType *rvalue, const char *name,
- TType *ptype1, TType *ptype2 = 0, TType *ptype3 = 0, TType *ptype4 = 0, TType *ptype5 = 0);
+ bool insertConstIntExt(ESymbolLevel level, const char *ext, const char *name, int value)
+ {
+ TVariable *constant =
+ new TVariable(NewPoolTString(name), TType(EbtInt, EbpUndefined, EvqConst, 1));
+ TConstantUnion *unionArray = new TConstantUnion[1];
+ unionArray[0].setIConst(value);
+ constant->shareConstPointer(unionArray);
+ return insert(level, ext, constant);
+ }
+
+ void insertBuiltIn(ESymbolLevel level, TOperator op, const char *ext, const TType *rvalue, const char *name,
+ const TType *ptype1, const TType *ptype2 = 0, const TType *ptype3 = 0, const TType *ptype4 = 0, const TType *ptype5 = 0);
- void insertBuiltIn(ESymbolLevel level, TType *rvalue, const char *name,
- TType *ptype1, TType *ptype2 = 0, TType *ptype3 = 0, TType *ptype4 = 0, TType *ptype5 = 0)
+ void insertBuiltIn(ESymbolLevel level, const TType *rvalue, const char *name,
+ const TType *ptype1, const TType *ptype2 = 0, const TType *ptype3 = 0, const TType *ptype4 = 0, const TType *ptype5 = 0)
{
insertBuiltIn(level, EOpNull, "", rvalue, name, ptype1, ptype2, ptype3, ptype4, ptype5);
}
- void insertBuiltIn(ESymbolLevel level, const char *ext, TType *rvalue, const char *name,
- TType *ptype1, TType *ptype2 = 0, TType *ptype3 = 0, TType *ptype4 = 0, TType *ptype5 = 0)
+ void insertBuiltIn(ESymbolLevel level, const char *ext, const TType *rvalue, const char *name,
+ const TType *ptype1, const TType *ptype2 = 0, const TType *ptype3 = 0, const TType *ptype4 = 0, const TType *ptype5 = 0)
{
insertBuiltIn(level, EOpNull, ext, rvalue, name, ptype1, ptype2, ptype3, ptype4, ptype5);
}
- void insertBuiltIn(ESymbolLevel level, TOperator op, TType *rvalue, const char *name,
- TType *ptype1, TType *ptype2 = 0, TType *ptype3 = 0, TType *ptype4 = 0, TType *ptype5 = 0)
+ void insertBuiltIn(ESymbolLevel level, TOperator op, const TType *rvalue, const char *name,
+ const TType *ptype1, const TType *ptype2 = 0, const TType *ptype3 = 0, const TType *ptype4 = 0, const TType *ptype5 = 0)
{
insertBuiltIn(level, op, "", rvalue, name, ptype1, ptype2, ptype3, ptype4, ptype5);
}
@@ -405,6 +436,8 @@ class TSymbolTable : angle::NonCopyable
{
if (!SupportsPrecision(type.type))
return false;
+ if (type.type == EbtUInt)
+ return false; // ESSL 3.00.4 section 4.5.4
if (type.isAggregate())
return false; // Not allowed to set for aggregate types
int indexOfLastElement = static_cast<int>(precisionStack.size()) - 1;
diff --git a/src/3rdparty/angle/src/compiler/translator/TranslatorESSL.cpp b/src/3rdparty/angle/src/compiler/translator/TranslatorESSL.cpp
index 238bc97576..76d006fd11 100644
--- a/src/3rdparty/angle/src/compiler/translator/TranslatorESSL.cpp
+++ b/src/3rdparty/angle/src/compiler/translator/TranslatorESSL.cpp
@@ -8,6 +8,7 @@
#include "compiler/translator/BuiltInFunctionEmulatorGLSL.h"
#include "compiler/translator/EmulatePrecision.h"
+#include "compiler/translator/RecordConstantPrecision.h"
#include "compiler/translator/OutputESSL.h"
#include "angle_gl.h"
@@ -19,16 +20,18 @@ TranslatorESSL::TranslatorESSL(sh::GLenum type, ShShaderSpec spec)
void TranslatorESSL::initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu, int compileOptions)
{
if (compileOptions & SH_EMULATE_BUILT_IN_FUNCTIONS)
- InitBuiltInFunctionEmulatorForGLSL(emu, getShaderType());
+ {
+ InitBuiltInFunctionEmulatorForGLSLWorkarounds(emu, getShaderType());
+ }
}
void TranslatorESSL::translate(TIntermNode *root, int) {
TInfoSinkBase& sink = getInfoSink().obj;
- int shaderVersion = getShaderVersion();
- if (shaderVersion > 100)
+ int shaderVer = getShaderVersion();
+ if (shaderVer > 100)
{
- sink << "#version " << shaderVersion << " es\n";
+ sink << "#version " << shaderVer << " es\n";
}
writePragma();
@@ -40,12 +43,14 @@ void TranslatorESSL::translate(TIntermNode *root, int) {
if (precisionEmulation)
{
- EmulatePrecision emulatePrecision;
+ EmulatePrecision emulatePrecision(getSymbolTable(), shaderVer);
root->traverse(&emulatePrecision);
emulatePrecision.updateTree();
emulatePrecision.writeEmulationHelpers(sink, SH_ESSL_OUTPUT);
}
+ RecordConstantPrecision(root, getTemporaryIndex());
+
// Write emulated built-in functions if needed.
if (!getBuiltInFunctionEmulator().IsOutputEmpty())
{
@@ -71,13 +76,8 @@ void TranslatorESSL::translate(TIntermNode *root, int) {
getArrayBoundsClamper().OutputClampingFunctionDefinition(sink);
// Write translated shader.
- TOutputESSL outputESSL(sink,
- getArrayIndexClampingStrategy(),
- getHashFunction(),
- getNameMap(),
- getSymbolTable(),
- shaderVersion,
- precisionEmulation);
+ TOutputESSL outputESSL(sink, getArrayIndexClampingStrategy(), getHashFunction(), getNameMap(),
+ getSymbolTable(), shaderVer, precisionEmulation);
root->traverse(&outputESSL);
}
diff --git a/src/3rdparty/angle/src/compiler/translator/TranslatorESSL.h b/src/3rdparty/angle/src/compiler/translator/TranslatorESSL.h
index 89a3e473e9..2cc61074d4 100644
--- a/src/3rdparty/angle/src/compiler/translator/TranslatorESSL.h
+++ b/src/3rdparty/angle/src/compiler/translator/TranslatorESSL.h
@@ -17,7 +17,7 @@ class TranslatorESSL : public TCompiler
protected:
void initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu, int compileOptions) override;
- virtual void translate(TIntermNode *root, int compileOptions);
+ void translate(TIntermNode *root, int compileOptions) override;
private:
void writeExtensionBehavior();
diff --git a/src/3rdparty/angle/src/compiler/translator/TranslatorGLSL.cpp b/src/3rdparty/angle/src/compiler/translator/TranslatorGLSL.cpp
index aea3f77c4e..05e9eb310b 100644
--- a/src/3rdparty/angle/src/compiler/translator/TranslatorGLSL.cpp
+++ b/src/3rdparty/angle/src/compiler/translator/TranslatorGLSL.cpp
@@ -9,53 +9,10 @@
#include "angle_gl.h"
#include "compiler/translator/BuiltInFunctionEmulatorGLSL.h"
#include "compiler/translator/EmulatePrecision.h"
+#include "compiler/translator/ExtensionGLSL.h"
#include "compiler/translator/OutputGLSL.h"
#include "compiler/translator/VersionGLSL.h"
-namespace
-{
-
-// To search for what output variables are used in a fragment shader.
-// We handle gl_FragColor and gl_FragData at the moment.
-class TFragmentOutSearcher : public TIntermTraverser
-{
- public:
- TFragmentOutSearcher()
- : mUsesGlFragColor(false),
- mUsesGlFragData(false)
- {
- }
-
- bool usesGlFragColor() const
- {
- return mUsesGlFragColor;
- }
-
- bool usesGlFragData() const
- {
- return mUsesGlFragData;
- }
-
- protected:
- virtual void visitSymbol(TIntermSymbol *node) override
- {
- if (node->getSymbol() == "gl_FragColor")
- {
- mUsesGlFragColor = true;
- }
- else if (node->getSymbol() == "gl_FragData")
- {
- mUsesGlFragData = true;
- }
- }
-
- private:
- bool mUsesGlFragColor;
- bool mUsesGlFragData;
-};
-
-} // namespace anonymous
-
TranslatorGLSL::TranslatorGLSL(sh::GLenum type,
ShShaderSpec spec,
ShShaderOutput output)
@@ -65,10 +22,16 @@ TranslatorGLSL::TranslatorGLSL(sh::GLenum type,
void TranslatorGLSL::initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu, int compileOptions)
{
if (compileOptions & SH_EMULATE_BUILT_IN_FUNCTIONS)
- InitBuiltInFunctionEmulatorForGLSL(emu, getShaderType());
+ {
+ InitBuiltInFunctionEmulatorForGLSLWorkarounds(emu, getShaderType());
+ }
+
+ int targetGLSLVersion = ShaderOutputTypeToGLSLVersion(getOutputType());
+ InitBuiltInFunctionEmulatorForGLSLMissingFunctions(emu, getShaderType(), targetGLSLVersion);
}
-void TranslatorGLSL::translate(TIntermNode *root, int) {
+void TranslatorGLSL::translate(TIntermNode *root, int compileOptions)
+{
TInfoSinkBase& sink = getInfoSink().obj;
// Write GLSL version.
@@ -77,13 +40,13 @@ void TranslatorGLSL::translate(TIntermNode *root, int) {
writePragma();
// Write extension behaviour as needed
- writeExtensionBehavior();
+ writeExtensionBehavior(root);
bool precisionEmulation = getResources().WEBGL_debug_shader_precision && getPragma().debugShaderPrecision;
if (precisionEmulation)
{
- EmulatePrecision emulatePrecision;
+ EmulatePrecision emulatePrecision(getSymbolTable(), getShaderVersion());
root->traverse(&emulatePrecision);
emulatePrecision.updateTree();
emulatePrecision.writeEmulationHelpers(sink, getOutputType());
@@ -103,20 +66,70 @@ void TranslatorGLSL::translate(TIntermNode *root, int) {
// Declare gl_FragColor and glFragData as webgl_FragColor and webgl_FragData
// if it's core profile shaders and they are used.
- if (getShaderType() == GL_FRAGMENT_SHADER &&
- getOutputType() == SH_GLSL_CORE_OUTPUT)
+ if (getShaderType() == GL_FRAGMENT_SHADER)
{
- TFragmentOutSearcher searcher;
- root->traverse(&searcher);
- ASSERT(!(searcher.usesGlFragData() && searcher.usesGlFragColor()));
- if (searcher.usesGlFragColor())
+ const bool mayHaveESSL1SecondaryOutputs =
+ IsExtensionEnabled(getExtensionBehavior(), "GL_EXT_blend_func_extended") &&
+ getShaderVersion() == 100;
+ const bool declareGLFragmentOutputs = IsGLSL130OrNewer(getOutputType());
+
+ bool hasGLFragColor = false;
+ bool hasGLFragData = false;
+ bool hasGLSecondaryFragColor = false;
+ bool hasGLSecondaryFragData = false;
+
+ for (const auto &outputVar : outputVariables)
+ {
+ if (declareGLFragmentOutputs)
+ {
+ if (outputVar.name == "gl_FragColor")
+ {
+ ASSERT(!hasGLFragColor);
+ hasGLFragColor = true;
+ continue;
+ }
+ else if (outputVar.name == "gl_FragData")
+ {
+ ASSERT(!hasGLFragData);
+ hasGLFragData = true;
+ continue;
+ }
+ }
+ if (mayHaveESSL1SecondaryOutputs)
+ {
+ if (outputVar.name == "gl_SecondaryFragColorEXT")
+ {
+ ASSERT(!hasGLSecondaryFragColor);
+ hasGLSecondaryFragColor = true;
+ continue;
+ }
+ else if (outputVar.name == "gl_SecondaryFragDataEXT")
+ {
+ ASSERT(!hasGLSecondaryFragData);
+ hasGLSecondaryFragData = true;
+ continue;
+ }
+ }
+ }
+ ASSERT(!((hasGLFragColor || hasGLSecondaryFragColor) &&
+ (hasGLFragData || hasGLSecondaryFragData)));
+ if (hasGLFragColor)
{
sink << "out vec4 webgl_FragColor;\n";
}
- if (searcher.usesGlFragData())
+ if (hasGLFragData)
{
sink << "out vec4 webgl_FragData[gl_MaxDrawBuffers];\n";
}
+ if (hasGLSecondaryFragColor)
+ {
+ sink << "out vec4 angle_SecondaryFragColor;\n";
+ }
+ if (hasGLSecondaryFragData)
+ {
+ sink << "out vec4 angle_SecondaryFragData[" << getResources().MaxDualSourceDrawBuffers
+ << "];\n";
+ }
}
// Write translated shader.
@@ -144,19 +157,41 @@ void TranslatorGLSL::writeVersion(TIntermNode *root)
}
}
-void TranslatorGLSL::writeExtensionBehavior() {
+void TranslatorGLSL::writeExtensionBehavior(TIntermNode *root)
+{
TInfoSinkBase& sink = getInfoSink().obj;
const TExtensionBehavior& extBehavior = getExtensionBehavior();
- for (TExtensionBehavior::const_iterator iter = extBehavior.begin();
- iter != extBehavior.end(); ++iter) {
- if (iter->second == EBhUndefined)
+ for (const auto &iter : extBehavior)
+ {
+ if (iter.second == EBhUndefined)
+ {
continue;
+ }
// For GLSL output, we don't need to emit most extensions explicitly,
// but some we need to translate.
- if (iter->first == "GL_EXT_shader_texture_lod") {
- sink << "#extension GL_ARB_shader_texture_lod : "
- << getBehaviorString(iter->second) << "\n";
+ if (iter.first == "GL_EXT_shader_texture_lod")
+ {
+ sink << "#extension GL_ARB_shader_texture_lod : " << getBehaviorString(iter.second)
+ << "\n";
}
}
+
+ // GLSL ES 3 explicit location qualifiers need to use an extension before GLSL 330
+ if (getShaderVersion() >= 300 && getOutputType() < SH_GLSL_330_CORE_OUTPUT)
+ {
+ sink << "#extension GL_ARB_explicit_attrib_location : require\n";
+ }
+
+ TExtensionGLSL extensionGLSL(getOutputType());
+ root->traverse(&extensionGLSL);
+
+ for (const auto &ext : extensionGLSL.getEnabledExtensions())
+ {
+ sink << "#extension " << ext << " : enable\n";
+ }
+ for (const auto &ext : extensionGLSL.getRequiredExtensions())
+ {
+ sink << "#extension " << ext << " : require\n";
+ }
}
diff --git a/src/3rdparty/angle/src/compiler/translator/TranslatorGLSL.h b/src/3rdparty/angle/src/compiler/translator/TranslatorGLSL.h
index 4a5a641096..4f07b21980 100644
--- a/src/3rdparty/angle/src/compiler/translator/TranslatorGLSL.h
+++ b/src/3rdparty/angle/src/compiler/translator/TranslatorGLSL.h
@@ -17,11 +17,11 @@ class TranslatorGLSL : public TCompiler
protected:
void initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu, int compileOptions) override;
- virtual void translate(TIntermNode *root, int compileOptions);
+ void translate(TIntermNode *root, int compileOptions) override;
private:
void writeVersion(TIntermNode *root);
- void writeExtensionBehavior();
+ void writeExtensionBehavior(TIntermNode *root);
};
#endif // COMPILER_TRANSLATOR_TRANSLATORGLSL_H_
diff --git a/src/3rdparty/angle/src/compiler/translator/TranslatorHLSL.cpp b/src/3rdparty/angle/src/compiler/translator/TranslatorHLSL.cpp
index f6275defa1..c5d18d21bf 100644
--- a/src/3rdparty/angle/src/compiler/translator/TranslatorHLSL.cpp
+++ b/src/3rdparty/angle/src/compiler/translator/TranslatorHLSL.cpp
@@ -6,8 +6,14 @@
#include "compiler/translator/TranslatorHLSL.h"
+#include "compiler/translator/ArrayReturnValueToOutParameter.h"
#include "compiler/translator/OutputHLSL.h"
-#include "compiler/translator/SimplifyArrayAssignment.h"
+#include "compiler/translator/RemoveDynamicIndexing.h"
+#include "compiler/translator/RewriteElseBlocks.h"
+#include "compiler/translator/SeparateArrayInitialization.h"
+#include "compiler/translator/SeparateDeclarations.h"
+#include "compiler/translator/SeparateExpressionsReturningArrays.h"
+#include "compiler/translator/UnfoldShortCircuitToIf.h"
TranslatorHLSL::TranslatorHLSL(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output)
: TCompiler(type, spec, output)
@@ -19,8 +25,32 @@ void TranslatorHLSL::translate(TIntermNode *root, int compileOptions)
const ShBuiltInResources &resources = getResources();
int numRenderTargets = resources.EXT_draw_buffers ? resources.MaxDrawBuffers : 1;
- SimplifyArrayAssignment simplify;
- root->traverse(&simplify);
+ SeparateDeclarations(root);
+
+ // Note that SeparateDeclarations needs to be run before UnfoldShortCircuitToIf.
+ UnfoldShortCircuitToIf(root, getTemporaryIndex());
+
+ SeparateExpressionsReturningArrays(root, getTemporaryIndex());
+
+ // Note that SeparateDeclarations needs to be run before SeparateArrayInitialization.
+ SeparateArrayInitialization(root);
+
+ // HLSL doesn't support arrays as return values, we'll need to make functions that have an array
+ // as a return value to use an out parameter to transfer the array data instead.
+ ArrayReturnValueToOutParameter(root, getTemporaryIndex());
+
+ if (!shouldRunLoopAndIndexingValidation(compileOptions))
+ {
+ // HLSL doesn't support dynamic indexing of vectors and matrices.
+ RemoveDynamicIndexing(root, getTemporaryIndex(), getSymbolTable(), getShaderVersion());
+ }
+
+ // 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 (getOutputType() == SH_HLSL_3_0_OUTPUT && getShaderType() == GL_VERTEX_SHADER)
+ {
+ sh::RewriteElseBlocks(root, getTemporaryIndex());
+ }
sh::OutputHLSL outputHLSL(getShaderType(), getShaderVersion(), getExtensionBehavior(),
getSourcePath(), getOutputType(), numRenderTargets, getUniforms(), compileOptions);
diff --git a/src/3rdparty/angle/src/compiler/translator/TranslatorHLSL.h b/src/3rdparty/angle/src/compiler/translator/TranslatorHLSL.h
index 1920ed5755..907d816744 100644
--- a/src/3rdparty/angle/src/compiler/translator/TranslatorHLSL.h
+++ b/src/3rdparty/angle/src/compiler/translator/TranslatorHLSL.h
@@ -13,7 +13,7 @@ class TranslatorHLSL : public TCompiler
{
public:
TranslatorHLSL(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output);
- virtual TranslatorHLSL *getAsTranslatorHLSL() { return this; }
+ TranslatorHLSL *getAsTranslatorHLSL() override { return this; }
bool hasInterfaceBlock(const std::string &interfaceBlockName) const;
unsigned int getInterfaceBlockRegister(const std::string &interfaceBlockName) const;
@@ -22,7 +22,10 @@ class TranslatorHLSL : public TCompiler
unsigned int getUniformRegister(const std::string &uniformName) const;
protected:
- virtual void translate(TIntermNode *root, int compileOptions);
+ void translate(TIntermNode *root, int compileOptions) override;
+
+ // collectVariables needs to be run always so registers can be assigned.
+ bool shouldCollectVariables(int compileOptions) override { return true; }
std::map<std::string, unsigned int> mInterfaceBlockRegisterMap;
std::map<std::string, unsigned int> mUniformRegisterMap;
diff --git a/src/3rdparty/angle/src/compiler/translator/Types.cpp b/src/3rdparty/angle/src/compiler/translator/Types.cpp
index b970bf5ac4..87fdfe0d54 100644
--- a/src/3rdparty/angle/src/compiler/translator/Types.cpp
+++ b/src/3rdparty/angle/src/compiler/translator/Types.cpp
@@ -46,9 +46,9 @@ const char* getBasicString(TBasicType t)
}
TType::TType(const TPublicType &p)
- : type(p.type), precision(p.precision), qualifier(p.qualifier), layoutQualifier(p.layoutQualifier),
- primarySize(p.primarySize), secondarySize(p.secondarySize), array(p.array), arraySize(p.arraySize),
- interfaceBlock(0), structure(0)
+ : type(p.type), precision(p.precision), qualifier(p.qualifier), invariant(p.invariant),
+ layoutQualifier(p.layoutQualifier), primarySize(p.primarySize), secondarySize(p.secondarySize),
+ array(p.array), arraySize(p.arraySize), interfaceBlock(0), structure(0)
{
if (p.userDef)
structure = p.userDef->getStruct();
@@ -59,6 +59,27 @@ bool TStructure::equals(const TStructure &other) const
return (uniqueId() == other.uniqueId());
}
+TString TType::getCompleteString() const
+{
+ TStringStream stream;
+
+ if (invariant)
+ stream << "invariant ";
+ if (qualifier != EvqTemporary && qualifier != EvqGlobal)
+ stream << getQualifierString() << " ";
+ if (precision != EbpUndefined)
+ stream << getPrecisionString() << " ";
+ if (array)
+ stream << "array[" << getArraySize() << "] of ";
+ if (isMatrix())
+ stream << getCols() << "X" << getRows() << " matrix of ";
+ else if (isVector())
+ stream << getNominalSize() << "-component vector of ";
+
+ stream << getBasicString();
+ return stream.str();
+}
+
//
// Recursively generate mangled names.
//
@@ -142,7 +163,8 @@ TString TType::buildMangledName() const
mangledName += interfaceBlock->mangledName();
break;
default:
- UNREACHABLE();
+ // EbtVoid, EbtAddress and non types
+ break;
}
if (isMatrix())
@@ -200,6 +222,17 @@ bool TStructure::containsArrays() const
return false;
}
+bool TStructure::containsType(TBasicType type) const
+{
+ for (size_t i = 0; i < mFields->size(); ++i)
+ {
+ const TType *fieldType = (*mFields)[i]->type();
+ if (fieldType->getBasicType() == type || fieldType->isStructureContainingType(type))
+ return true;
+ }
+ return false;
+}
+
bool TStructure::containsSamplers() const
{
for (size_t i = 0; i < mFields->size(); ++i)
@@ -211,9 +244,9 @@ bool TStructure::containsSamplers() const
return false;
}
-TString TFieldListCollection::buildMangledName() const
+TString TFieldListCollection::buildMangledName(const TString &mangledNamePrefix) const
{
- TString mangledName(mangledNamePrefix());
+ TString mangledName(mangledNamePrefix);
mangledName += *mName;
for (size_t i = 0; i < mFields->size(); ++i)
{
diff --git a/src/3rdparty/angle/src/compiler/translator/Types.h b/src/3rdparty/angle/src/compiler/translator/Types.h
index 044f22c3c1..c2968dceba 100644
--- a/src/3rdparty/angle/src/compiler/translator/Types.h
+++ b/src/3rdparty/angle/src/compiler/translator/Types.h
@@ -8,10 +8,10 @@
#define COMPILER_TRANSLATOR_TYPES_H_
#include "common/angleutils.h"
+#include "common/debug.h"
#include "compiler/translator/BaseTypes.h"
#include "compiler/translator/Common.h"
-#include "compiler/translator/compilerdebug.h"
struct TPublicType;
class TType;
@@ -73,12 +73,6 @@ class TFieldListCollection : angle::NonCopyable
return *mFields;
}
- const TString &mangledName() const
- {
- if (mMangledName.empty())
- mMangledName = buildMangledName();
- return mMangledName;
- }
size_t objectSize() const
{
if (mObjectSize == 0)
@@ -93,9 +87,8 @@ class TFieldListCollection : angle::NonCopyable
mObjectSize(0)
{
}
- TString buildMangledName() const;
+ TString buildMangledName(const TString &mangledNamePrefix) const;
size_t calculateObjectSize() const;
- virtual TString mangledNamePrefix() const = 0;
const TString *mName;
TFieldList *mFields;
@@ -124,6 +117,7 @@ class TStructure : public TFieldListCollection
return mDeepestNesting;
}
bool containsArrays() const;
+ bool containsType(TBasicType t) const;
bool containsSamplers() const;
bool equals(const TStructure &other) const;
@@ -149,6 +143,13 @@ class TStructure : public TFieldListCollection
return mAtGlobalScope;
}
+ const TString &mangledName() const
+ {
+ if (mMangledName.empty())
+ mMangledName = buildMangledName("struct-");
+ return mMangledName;
+ }
+
private:
// TODO(zmo): Find a way to get rid of the const_cast in function
// setName(). At the moment keep this function private so only
@@ -160,10 +161,6 @@ class TStructure : public TFieldListCollection
*mutableName = name;
}
- virtual TString mangledNamePrefix() const
- {
- return "struct-";
- }
int calculateDeepestNesting() const;
mutable int mDeepestNesting;
@@ -209,13 +206,14 @@ class TInterfaceBlock : public TFieldListCollection
{
return mMatrixPacking;
}
-
- private:
- virtual TString mangledNamePrefix() const
+ const TString &mangledName() const
{
- return "iblock-";
+ if (mMangledName.empty())
+ mMangledName = buildMangledName("iblock-");
+ return mMangledName;
}
+ private:
const TString *mInstanceName; // for interface block instance names
int mArraySize; // 0 if not an array
TLayoutBlockStorage mBlockStorage;
@@ -230,10 +228,14 @@ class TType
public:
POOL_ALLOCATOR_NEW_DELETE();
TType()
+ : type(EbtVoid), precision(EbpUndefined), qualifier(EvqGlobal), invariant(false),
+ layoutQualifier(TLayoutQualifier::create()),
+ primarySize(0), secondarySize(0), array(false), arraySize(0),
+ interfaceBlock(nullptr), structure(nullptr)
{
}
TType(TBasicType t, unsigned char ps = 1, unsigned char ss = 1)
- : type(t), precision(EbpUndefined), qualifier(EvqGlobal),
+ : type(t), precision(EbpUndefined), qualifier(EvqGlobal), invariant(false),
layoutQualifier(TLayoutQualifier::create()),
primarySize(ps), secondarySize(ss), array(false), arraySize(0),
interfaceBlock(0), structure(0)
@@ -241,7 +243,7 @@ class TType
}
TType(TBasicType t, TPrecision p, TQualifier q = EvqTemporary,
unsigned char ps = 1, unsigned char ss = 1, bool a = false)
- : type(t), precision(p), qualifier(q),
+ : type(t), precision(p), qualifier(q), invariant(false),
layoutQualifier(TLayoutQualifier::create()),
primarySize(ps), secondarySize(ss), array(a), arraySize(0),
interfaceBlock(0), structure(0)
@@ -249,7 +251,7 @@ class TType
}
explicit TType(const TPublicType &p);
TType(TStructure *userDef, TPrecision p = EbpUndefined)
- : type(EbtStruct), precision(p), qualifier(EvqTemporary),
+ : type(EbtStruct), precision(p), qualifier(EvqTemporary), invariant(false),
layoutQualifier(TLayoutQualifier::create()),
primarySize(1), secondarySize(1), array(false), arraySize(0),
interfaceBlock(0), structure(userDef)
@@ -258,19 +260,26 @@ class TType
TType(TInterfaceBlock *interfaceBlockIn, TQualifier qualifierIn,
TLayoutQualifier layoutQualifierIn, int arraySizeIn)
: type(EbtInterfaceBlock), precision(EbpUndefined), qualifier(qualifierIn),
- layoutQualifier(layoutQualifierIn),
+ invariant(false), layoutQualifier(layoutQualifierIn),
primarySize(1), secondarySize(1), array(arraySizeIn > 0), arraySize(arraySizeIn),
interfaceBlock(interfaceBlockIn), structure(0)
{
}
+ TType(const TType &) = default;
+ TType &operator=(const TType &) = default;
+
TBasicType getBasicType() const
{
return type;
}
void setBasicType(TBasicType t)
{
- type = t;
+ if (type != t)
+ {
+ type = t;
+ invalidateMangledName();
+ }
}
TPrecision getPrecision() const
@@ -291,6 +300,11 @@ class TType
qualifier = q;
}
+ bool isInvariant() const
+ {
+ return invariant;
+ }
+
TLayoutQualifier getLayoutQualifier() const
{
return layoutQualifier;
@@ -320,11 +334,19 @@ class TType
}
void setPrimarySize(unsigned char ps)
{
- primarySize = ps;
+ if (primarySize != ps)
+ {
+ primarySize = ps;
+ invalidateMangledName();
+ }
}
void setSecondarySize(unsigned char ss)
{
- secondarySize = ss;
+ if (secondarySize != ss)
+ {
+ secondarySize = ss;
+ invalidateMangledName();
+ }
}
// Full size of single instance of type
@@ -340,7 +362,11 @@ class TType
}
bool isArray() const
{
- return array ? true : false;
+ return array;
+ }
+ bool isUnsizedArray() const
+ {
+ return array && arraySize == 0;
}
int getArraySize() const
{
@@ -348,13 +374,21 @@ class TType
}
void setArraySize(int s)
{
- array = true;
- arraySize = s;
+ if (!array || arraySize != s)
+ {
+ array = true;
+ arraySize = s;
+ invalidateMangledName();
+ }
}
void clearArrayness()
{
- array = false;
- arraySize = 0;
+ if (array)
+ {
+ array = false;
+ arraySize = 0;
+ invalidateMangledName();
+ }
}
TInterfaceBlock *getInterfaceBlock() const
@@ -363,7 +397,11 @@ class TType
}
void setInterfaceBlock(TInterfaceBlock *interfaceBlockIn)
{
- interfaceBlock = interfaceBlockIn;
+ if (interfaceBlock != interfaceBlockIn)
+ {
+ interfaceBlock = interfaceBlockIn;
+ invalidateMangledName();
+ }
}
bool isInterfaceBlock() const
{
@@ -389,10 +427,14 @@ class TType
}
void setStruct(TStructure *s)
{
- structure = s;
+ if (structure != s)
+ {
+ structure = s;
+ invalidateMangledName();
+ }
}
- const TString &getMangledName()
+ const TString &getMangledName() const
{
if (mangled.empty())
{
@@ -477,19 +519,31 @@ class TType
return structure ? structure->containsArrays() : false;
}
+ bool isStructureContainingType(TBasicType t) const
+ {
+ return structure ? structure->containsType(t) : false;
+ }
+
bool isStructureContainingSamplers() const
{
return structure ? structure->containsSamplers() : false;
}
- protected:
+ // Initializes all lazily-initialized members.
+ void realize()
+ {
+ getMangledName();
+ }
+
+ private:
+ void invalidateMangledName() { mangled = ""; }
TString buildMangledName() const;
size_t getStructSize() const;
- void computeDeepestStructNesting();
TBasicType type;
TPrecision precision;
TQualifier qualifier;
+ bool invariant;
TLayoutQualifier layoutQualifier;
unsigned char primarySize; // size of vector or cols matrix
unsigned char secondarySize; // rows of a matrix
@@ -519,6 +573,7 @@ struct TPublicType
TBasicType type;
TLayoutQualifier layoutQualifier;
TQualifier qualifier;
+ bool invariant;
TPrecision precision;
unsigned char primarySize; // size of vector or cols of matrix
unsigned char secondarySize; // rows of matrix
@@ -527,11 +582,15 @@ struct TPublicType
TType *userDef;
TSourceLoc line;
+ // true if the type was defined by a struct specifier rather than a reference to a type name.
+ bool isStructSpecifier;
+
void setBasic(TBasicType bt, TQualifier q, const TSourceLoc &ln)
{
type = bt;
layoutQualifier = TLayoutQualifier::create();
qualifier = q;
+ invariant = false;
precision = EbpUndefined;
primarySize = 1;
secondarySize = 1;
@@ -539,6 +598,7 @@ struct TPublicType
arraySize = 0;
userDef = 0;
line = ln;
+ isStructSpecifier = false;
}
void setAggregate(unsigned char size)
@@ -553,11 +613,20 @@ struct TPublicType
secondarySize = r;
}
- void setArray(bool a, int s = 0)
+ bool isUnsizedArray() const
{
- array = a;
+ return array && arraySize == 0;
+ }
+ void setArraySize(int s)
+ {
+ array = true;
arraySize = s;
}
+ void clearArrayness()
+ {
+ array = false;
+ arraySize = 0;
+ }
bool isStructureContainingArrays() const
{
@@ -569,6 +638,16 @@ struct TPublicType
return userDef->isStructureContainingArrays();
}
+ bool isStructureContainingType(TBasicType t) const
+ {
+ if (!userDef)
+ {
+ return false;
+ }
+
+ return userDef->isStructureContainingType(t);
+ }
+
bool isMatrix() const
{
return primarySize > 1 && secondarySize > 1;
diff --git a/src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuitAST.cpp b/src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuitAST.cpp
index d548d421d2..e50bf202ef 100644
--- a/src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuitAST.cpp
+++ b/src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuitAST.cpp
@@ -13,7 +13,7 @@ namespace
TIntermSelection *UnfoldOR(TIntermTyped *x, TIntermTyped *y)
{
const TType boolType(EbtBool, EbpUndefined);
- ConstantUnion *u = new ConstantUnion;
+ TConstantUnion *u = new TConstantUnion;
u->setBConst(true);
TIntermConstantUnion *trueNode = new TIntermConstantUnion(
u, TType(EbtBool, EbpUndefined, EvqConst, 1));
@@ -24,7 +24,7 @@ TIntermSelection *UnfoldOR(TIntermTyped *x, TIntermTyped *y)
TIntermSelection *UnfoldAND(TIntermTyped *x, TIntermTyped *y)
{
const TType boolType(EbtBool, EbpUndefined);
- ConstantUnion *u = new ConstantUnion;
+ TConstantUnion *u = new TConstantUnion;
u->setBConst(false);
TIntermConstantUnion *falseNode = new TIntermConstantUnion(
u, TType(EbtBool, EbpUndefined, EvqConst, 1));
diff --git a/src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuitAST.h b/src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuitAST.h
index 7b698ccb63..b92a4e9152 100644
--- a/src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuitAST.h
+++ b/src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuitAST.h
@@ -20,9 +20,12 @@
class UnfoldShortCircuitAST : public TIntermTraverser
{
public:
- UnfoldShortCircuitAST() { }
+ UnfoldShortCircuitAST()
+ : TIntermTraverser(true, false, false)
+ {
+ }
- virtual bool visitBinary(Visit visit, TIntermBinary *);
+ bool visitBinary(Visit visit, TIntermBinary *) override;
};
#endif // COMPILER_TRANSLATOR_UNFOLDSHORTCIRCUITAST_H_
diff --git a/src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuitToIf.cpp b/src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuitToIf.cpp
new file mode 100644
index 0000000000..be23b524d7
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuitToIf.cpp
@@ -0,0 +1,368 @@
+//
+// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// UnfoldShortCircuitToIf is an AST traverser to convert short-circuiting operators to if-else statements.
+// The results are assigned to s# temporaries, which are used by the main translator instead of
+// the original expression.
+//
+
+#include "compiler/translator/UnfoldShortCircuitToIf.h"
+
+#include "compiler/translator/IntermNode.h"
+
+namespace
+{
+
+// Traverser that unfolds one short-circuiting operation at a time.
+class UnfoldShortCircuitTraverser : public TIntermTraverser
+{
+ public:
+ UnfoldShortCircuitTraverser();
+
+ bool visitBinary(Visit visit, TIntermBinary *node) override;
+ bool visitAggregate(Visit visit, TIntermAggregate *node) override;
+ bool visitSelection(Visit visit, TIntermSelection *node) override;
+ bool visitLoop(Visit visit, TIntermLoop *node) override;
+
+ void nextIteration();
+ bool foundShortCircuit() const { return mFoundShortCircuit; }
+
+ protected:
+ // Check if the traversal is inside a loop condition or expression, in which case the unfolded
+ // expression needs to be copied inside the loop. Returns true if the copying is done, in which
+ // case no further unfolding should be done on the same traversal.
+ // The parameters are the node that will be unfolded to multiple statements and so can't remain
+ // inside a loop condition, and its parent.
+ bool copyLoopConditionOrExpression(TIntermNode *parent, TIntermTyped *node);
+
+ // Marked to true once an operation that needs to be unfolded has been found.
+ // After that, no more unfolding is performed on that traversal.
+ bool mFoundShortCircuit;
+
+ // Set to the loop node while a loop condition or expression is being traversed.
+ TIntermLoop *mParentLoop;
+ // Parent of the loop node while a loop condition or expression is being traversed.
+ TIntermNode *mLoopParent;
+
+ bool mInLoopCondition;
+ bool mInLoopExpression;
+};
+
+UnfoldShortCircuitTraverser::UnfoldShortCircuitTraverser()
+ : TIntermTraverser(true, false, true),
+ mFoundShortCircuit(false),
+ mParentLoop(nullptr),
+ mLoopParent(nullptr),
+ mInLoopCondition(false),
+ mInLoopExpression(false)
+{
+}
+
+bool UnfoldShortCircuitTraverser::visitBinary(Visit visit, TIntermBinary *node)
+{
+ if (mFoundShortCircuit)
+ return false;
+ // If our right node doesn't have side effects, we know we don't need to unfold this
+ // expression: there will be no short-circuiting side effects to avoid
+ // (note: unfolding doesn't depend on the left node -- it will always be evaluated)
+ if (!node->getRight()->hasSideEffects())
+ {
+ return true;
+ }
+
+ switch (node->getOp())
+ {
+ case EOpLogicalOr:
+ mFoundShortCircuit = true;
+ if (!copyLoopConditionOrExpression(getParentNode(), node))
+ {
+ // "x || y" is equivalent to "x ? true : y", which unfolds to "bool s; if(x) s = true;
+ // else s = y;",
+ // and then further simplifies down to "bool s = x; if(!s) s = y;".
+
+ TIntermSequence insertions;
+ TType boolType(EbtBool, EbpUndefined, EvqTemporary);
+
+ ASSERT(node->getLeft()->getType() == boolType);
+ insertions.push_back(createTempInitDeclaration(node->getLeft()));
+
+ TIntermAggregate *assignRightBlock = new TIntermAggregate(EOpSequence);
+ ASSERT(node->getRight()->getType() == boolType);
+ assignRightBlock->getSequence()->push_back(createTempAssignment(node->getRight()));
+
+ TIntermUnary *notTempSymbol = new TIntermUnary(EOpLogicalNot, boolType);
+ notTempSymbol->setOperand(createTempSymbol(boolType));
+ TIntermSelection *ifNode = new TIntermSelection(notTempSymbol, assignRightBlock, nullptr);
+ insertions.push_back(ifNode);
+
+ insertStatementsInParentBlock(insertions);
+
+ NodeUpdateEntry replaceVariable(getParentNode(), node, createTempSymbol(boolType), false);
+ mReplacements.push_back(replaceVariable);
+ }
+ return false;
+ case EOpLogicalAnd:
+ mFoundShortCircuit = true;
+ if (!copyLoopConditionOrExpression(getParentNode(), node))
+ {
+ // "x && y" is equivalent to "x ? y : false", which unfolds to "bool s; if(x) s = y;
+ // else s = false;",
+ // and then further simplifies down to "bool s = x; if(s) s = y;".
+ TIntermSequence insertions;
+ TType boolType(EbtBool, EbpUndefined, EvqTemporary);
+
+ ASSERT(node->getLeft()->getType() == boolType);
+ insertions.push_back(createTempInitDeclaration(node->getLeft()));
+
+ TIntermAggregate *assignRightBlock = new TIntermAggregate(EOpSequence);
+ ASSERT(node->getRight()->getType() == boolType);
+ assignRightBlock->getSequence()->push_back(createTempAssignment(node->getRight()));
+
+ TIntermSelection *ifNode = new TIntermSelection(createTempSymbol(boolType), assignRightBlock, nullptr);
+ insertions.push_back(ifNode);
+
+ insertStatementsInParentBlock(insertions);
+
+ NodeUpdateEntry replaceVariable(getParentNode(), node, createTempSymbol(boolType), false);
+ mReplacements.push_back(replaceVariable);
+ }
+ return false;
+ default:
+ return true;
+ }
+}
+
+bool UnfoldShortCircuitTraverser::visitSelection(Visit visit, TIntermSelection *node)
+{
+ if (mFoundShortCircuit)
+ return false;
+
+ // Unfold "b ? x : y" into "type s; if(b) s = x; else s = y;"
+ if (visit == PreVisit && node->usesTernaryOperator())
+ {
+ mFoundShortCircuit = true;
+ if (!copyLoopConditionOrExpression(getParentNode(), node))
+ {
+ TIntermSequence insertions;
+
+ TIntermSymbol *tempSymbol = createTempSymbol(node->getType());
+ TIntermAggregate *tempDeclaration = new TIntermAggregate(EOpDeclaration);
+ tempDeclaration->getSequence()->push_back(tempSymbol);
+ insertions.push_back(tempDeclaration);
+
+ TIntermAggregate *trueBlock = new TIntermAggregate(EOpSequence);
+ TIntermBinary *trueAssignment =
+ createTempAssignment(node->getTrueBlock()->getAsTyped());
+ trueBlock->getSequence()->push_back(trueAssignment);
+
+ TIntermAggregate *falseBlock = new TIntermAggregate(EOpSequence);
+ TIntermBinary *falseAssignment =
+ createTempAssignment(node->getFalseBlock()->getAsTyped());
+ falseBlock->getSequence()->push_back(falseAssignment);
+
+ TIntermSelection *ifNode =
+ new TIntermSelection(node->getCondition()->getAsTyped(), trueBlock, falseBlock);
+ insertions.push_back(ifNode);
+
+ insertStatementsInParentBlock(insertions);
+
+ TIntermSymbol *ternaryResult = createTempSymbol(node->getType());
+ NodeUpdateEntry replaceVariable(getParentNode(), node, ternaryResult, false);
+ mReplacements.push_back(replaceVariable);
+ }
+ return false;
+ }
+
+ return true;
+}
+
+bool UnfoldShortCircuitTraverser::visitAggregate(Visit visit, TIntermAggregate *node)
+{
+ if (visit == PreVisit && mFoundShortCircuit)
+ return false; // No need to traverse further
+
+ if (node->getOp() == EOpComma)
+ {
+ ASSERT(visit != PreVisit || !mFoundShortCircuit);
+
+ if (visit == PostVisit && mFoundShortCircuit)
+ {
+ // We can be sure that we arrived here because there was a short-circuiting operator
+ // inside the sequence operator since we only start traversing the sequence operator in
+ // case a short-circuiting operator has not been found so far.
+ // We need to unfold the sequence (comma) operator, otherwise the evaluation order of
+ // statements would be messed up by unfolded operations inside.
+ // Don't do any other unfolding on this round of traversal.
+ mReplacements.clear();
+ mMultiReplacements.clear();
+ mInsertions.clear();
+
+ if (!copyLoopConditionOrExpression(getParentNode(), node))
+ {
+ TIntermSequence insertions;
+ TIntermSequence *seq = node->getSequence();
+
+ TIntermSequence::size_type i = 0;
+ ASSERT(!seq->empty());
+ while (i < seq->size() - 1)
+ {
+ TIntermTyped *child = (*seq)[i]->getAsTyped();
+ insertions.push_back(child);
+ ++i;
+ }
+
+ insertStatementsInParentBlock(insertions);
+
+ NodeUpdateEntry replaceVariable(getParentNode(), node, (*seq)[i], false);
+ mReplacements.push_back(replaceVariable);
+ }
+ }
+ }
+ return true;
+}
+
+bool UnfoldShortCircuitTraverser::visitLoop(Visit visit, TIntermLoop *node)
+{
+ if (visit == PreVisit)
+ {
+ if (mFoundShortCircuit)
+ return false; // No need to traverse further
+
+ mLoopParent = getParentNode();
+ mParentLoop = node;
+ incrementDepth(node);
+
+ if (node->getInit())
+ {
+ node->getInit()->traverse(this);
+ if (mFoundShortCircuit)
+ {
+ decrementDepth();
+ return false;
+ }
+ }
+
+ if (node->getCondition())
+ {
+ mInLoopCondition = true;
+ node->getCondition()->traverse(this);
+ mInLoopCondition = false;
+
+ if (mFoundShortCircuit)
+ {
+ decrementDepth();
+ return false;
+ }
+ }
+
+ if (node->getExpression())
+ {
+ mInLoopExpression = true;
+ node->getExpression()->traverse(this);
+ mInLoopExpression = false;
+
+ if (mFoundShortCircuit)
+ {
+ decrementDepth();
+ return false;
+ }
+ }
+
+ if (node->getBody())
+ node->getBody()->traverse(this);
+
+ decrementDepth();
+ }
+ return false;
+}
+
+bool UnfoldShortCircuitTraverser::copyLoopConditionOrExpression(TIntermNode *parent,
+ TIntermTyped *node)
+{
+ if (mInLoopCondition)
+ {
+ mReplacements.push_back(
+ NodeUpdateEntry(parent, node, createTempSymbol(node->getType()), false));
+ TIntermAggregate *body = mParentLoop->getBody();
+ TIntermSequence empty;
+ if (mParentLoop->getType() == ELoopDoWhile)
+ {
+ // Declare the temporary variable before the loop.
+ TIntermSequence insertionsBeforeLoop;
+ insertionsBeforeLoop.push_back(createTempDeclaration(node->getType()));
+ insertStatementsInParentBlock(insertionsBeforeLoop);
+
+ // Move a part of do-while loop condition to inside the loop.
+ TIntermSequence insertionsInLoop;
+ insertionsInLoop.push_back(createTempAssignment(node));
+ mInsertions.push_back(NodeInsertMultipleEntry(body, body->getSequence()->size() - 1,
+ empty, insertionsInLoop));
+ }
+ else
+ {
+ // The loop initializer expression and one copy of the part of the loop condition are
+ // executed before the loop. They need to be in a new scope.
+ TIntermAggregate *loopScope = new TIntermAggregate(EOpSequence);
+
+ TIntermNode *initializer = mParentLoop->getInit();
+ if (initializer != nullptr)
+ {
+ // Move the initializer to the newly created outer scope, so that condition can
+ // depend on it.
+ mReplacements.push_back(NodeUpdateEntry(mParentLoop, initializer, nullptr, false));
+ loopScope->getSequence()->push_back(initializer);
+ }
+
+ loopScope->getSequence()->push_back(createTempInitDeclaration(node));
+ loopScope->getSequence()->push_back(mParentLoop);
+ mReplacements.push_back(NodeUpdateEntry(mLoopParent, mParentLoop, loopScope, true));
+
+ // The second copy of the part of the loop condition is executed inside the loop.
+ TIntermSequence insertionsInLoop;
+ insertionsInLoop.push_back(createTempAssignment(node->deepCopy()));
+ mInsertions.push_back(NodeInsertMultipleEntry(body, body->getSequence()->size() - 1,
+ empty, insertionsInLoop));
+ }
+ return true;
+ }
+
+ if (mInLoopExpression)
+ {
+ TIntermTyped *movedExpression = mParentLoop->getExpression();
+ mReplacements.push_back(NodeUpdateEntry(mParentLoop, movedExpression, nullptr, false));
+ TIntermAggregate *body = mParentLoop->getBody();
+ TIntermSequence empty;
+ TIntermSequence insertions;
+ insertions.push_back(movedExpression);
+ mInsertions.push_back(
+ NodeInsertMultipleEntry(body, body->getSequence()->size() - 1, empty, insertions));
+ return true;
+ }
+ return false;
+}
+
+void UnfoldShortCircuitTraverser::nextIteration()
+{
+ mFoundShortCircuit = false;
+ nextTemporaryIndex();
+}
+
+} // namespace
+
+void UnfoldShortCircuitToIf(TIntermNode *root, unsigned int *temporaryIndex)
+{
+ UnfoldShortCircuitTraverser traverser;
+ ASSERT(temporaryIndex != nullptr);
+ traverser.useTemporaryIndex(temporaryIndex);
+ // Unfold one operator at a time, and reset the traverser between iterations.
+ do
+ {
+ traverser.nextIteration();
+ root->traverse(&traverser);
+ if (traverser.foundShortCircuit())
+ traverser.updateTree();
+ }
+ while (traverser.foundShortCircuit());
+}
diff --git a/src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuitToIf.h b/src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuitToIf.h
new file mode 100644
index 0000000000..0fe37b7140
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuitToIf.h
@@ -0,0 +1,18 @@
+//
+// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// UnfoldShortCircuitToIf is an AST traverser to convert short-circuiting operators to if-else statements.
+// The results are assigned to s# temporaries, which are used by the main translator instead of
+// the original expression.
+//
+
+#ifndef COMPILER_TRANSLATOR_UNFOLDSHORTCIRCUIT_H_
+#define COMPILER_TRANSLATOR_UNFOLDSHORTCIRCUIT_H_
+
+class TIntermNode;
+
+void UnfoldShortCircuitToIf(TIntermNode *root, unsigned int *temporaryIndex);
+
+#endif // COMPILER_TRANSLATOR_UNFOLDSHORTCIRCUIT_H_
diff --git a/src/3rdparty/angle/src/compiler/translator/UniformHLSL.cpp b/src/3rdparty/angle/src/compiler/translator/UniformHLSL.cpp
index 71659fe354..20961c44c1 100644
--- a/src/3rdparty/angle/src/compiler/translator/UniformHLSL.cpp
+++ b/src/3rdparty/angle/src/compiler/translator/UniformHLSL.cpp
@@ -93,7 +93,9 @@ const Uniform *UniformHLSL::findUniformByName(const TString &name) const
return NULL;
}
-unsigned int UniformHLSL::declareUniformAndAssignRegister(const TType &type, const TString &name)
+unsigned int UniformHLSL::declareUniformAndAssignRegister(const TType &type,
+ const TString &name,
+ unsigned int *registerCount)
{
unsigned int registerIndex = (IsSampler(type.getBasicType()) ? mSamplerRegister : mUniformRegister);
@@ -102,43 +104,119 @@ unsigned int UniformHLSL::declareUniformAndAssignRegister(const TType &type, con
mUniformRegisterMap[uniform->name] = registerIndex;
- unsigned int registerCount = HLSLVariableRegisterCount(*uniform, mOutputType);
+ ASSERT(registerCount);
+ *registerCount = HLSLVariableRegisterCount(*uniform, mOutputType);
if (gl::IsSamplerType(uniform->type))
{
- mSamplerRegister += registerCount;
+ mSamplerRegister += *registerCount;
}
else
{
- mUniformRegister += registerCount;
+ mUniformRegister += *registerCount;
}
return registerIndex;
}
-TString UniformHLSL::uniformsHeader(ShShaderOutput outputType, const ReferencedSymbols &referencedUniforms)
+unsigned int UniformHLSL::declareUniformAndAssignRegister(const TType &type, const TString &name)
+{
+ unsigned int registerCount;
+ return declareUniformAndAssignRegister(type, name, &registerCount);
+}
+
+void UniformHLSL::outputHLSLSamplerUniformGroup(TInfoSinkBase &out,
+ const HLSLTextureSamplerGroup textureGroup,
+ const TVector<const TIntermSymbol *> &group,
+ unsigned int *groupTextureRegisterIndex)
{
- TString uniforms;
+ if (group.empty())
+ {
+ return;
+ }
+ unsigned int groupRegisterCount = 0;
+ for (const TIntermSymbol *uniform : group)
+ {
+ const TType &type = uniform->getType();
+ const TString &name = uniform->getSymbol();
+ unsigned int registerCount;
+ unsigned int samplerArrayIndex =
+ declareUniformAndAssignRegister(type, name, &registerCount);
+ groupRegisterCount += registerCount;
+ if (type.isArray())
+ {
+ out << "static const uint " << DecorateIfNeeded(uniform->getName()) << ArrayString(type)
+ << " = {";
+ for (int i = 0; i < type.getArraySize(); ++i)
+ {
+ if (i > 0)
+ out << ", ";
+ out << (samplerArrayIndex + i);
+ }
+ out << "};\n";
+ }
+ else
+ {
+ out << "static const uint " << DecorateIfNeeded(uniform->getName()) << " = "
+ << samplerArrayIndex << ";\n";
+ }
+ }
+ TString suffix = TextureGroupSuffix(textureGroup);
+ // Since HLSL_TEXTURE_2D is the first group, it has a fixed offset of zero.
+ if (textureGroup != HLSL_TEXTURE_2D)
+ {
+ out << "static const uint textureIndexOffset" << suffix << " = "
+ << (*groupTextureRegisterIndex) << ";\n";
+ out << "static const uint samplerIndexOffset" << suffix << " = "
+ << (*groupTextureRegisterIndex) << ";\n";
+ }
+ out << "uniform " << TextureString(textureGroup) << " textures" << suffix << "["
+ << groupRegisterCount << "]"
+ << " : register(t" << (*groupTextureRegisterIndex) << ");\n";
+ out << "uniform " << SamplerString(textureGroup) << " samplers" << suffix << "["
+ << groupRegisterCount << "]"
+ << " : register(s" << (*groupTextureRegisterIndex) << ");\n";
+ *groupTextureRegisterIndex += groupRegisterCount;
+}
- for (ReferencedSymbols::const_iterator uniformIt = referencedUniforms.begin();
- uniformIt != referencedUniforms.end(); uniformIt++)
+void UniformHLSL::uniformsHeader(TInfoSinkBase &out,
+ ShShaderOutput outputType,
+ const ReferencedSymbols &referencedUniforms)
+{
+ if (!referencedUniforms.empty())
+ {
+ out << "// Uniforms\n\n";
+ }
+ // In the case of HLSL 4, sampler uniforms need to be grouped by type before the code is
+ // written. They are grouped based on the combination of the HLSL texture type and
+ // HLSL sampler type, enumerated in HLSLTextureSamplerGroup.
+ TVector<TVector<const TIntermSymbol *>> groupedSamplerUniforms;
+ groupedSamplerUniforms.resize(HLSL_TEXTURE_MAX + 1);
+ for (auto &uniformIt : referencedUniforms)
{
- const TIntermSymbol &uniform = *uniformIt->second;
+ // Output regular uniforms. Group sampler uniforms by type.
+ const TIntermSymbol &uniform = *uniformIt.second;
const TType &type = uniform.getType();
const TString &name = uniform.getSymbol();
- unsigned int registerIndex = declareUniformAndAssignRegister(type, name);
-
- if (outputType == SH_HLSL11_OUTPUT && IsSampler(type.getBasicType())) // Also declare the texture
+ if (outputType == SH_HLSL_4_1_OUTPUT && IsSampler(type.getBasicType()))
{
- uniforms += "uniform " + SamplerString(type) + " sampler_" + DecorateUniform(name, type) + ArrayString(type) +
- " : register(s" + str(registerIndex) + ");\n";
-
- uniforms += "uniform " + TextureString(type) + " texture_" + DecorateUniform(name, type) + ArrayString(type) +
- " : register(t" + str(registerIndex) + ");\n";
+ HLSLTextureSamplerGroup group = TextureGroup(type.getBasicType());
+ groupedSamplerUniforms[group].push_back(&uniform);
+ }
+ else if (outputType == SH_HLSL_4_0_FL9_3_OUTPUT && IsSampler(type.getBasicType()))
+ {
+ unsigned int registerIndex = declareUniformAndAssignRegister(type, name);
+ out << "uniform " << SamplerString(type.getBasicType()) << " sampler_"
+ << DecorateUniform(name, type) << ArrayString(type) << " : register(s"
+ << str(registerIndex) << ");\n";
+ out << "uniform " << TextureString(type.getBasicType()) << " texture_"
+ << DecorateUniform(name, type) << ArrayString(type) << " : register(t"
+ << str(registerIndex) << ");\n";
}
else
{
+ unsigned int registerIndex = declareUniformAndAssignRegister(type, name);
const TStructure *structure = type.getStruct();
// If this is a nameless struct, we need to use its full definition, rather than its (empty) name.
// TypeString() will invoke defineNameless in this case; qualifier prefixes are unnecessary for
@@ -149,11 +227,23 @@ TString UniformHLSL::uniformsHeader(ShShaderOutput outputType, const ReferencedS
const TString &registerString = TString("register(") + UniformRegisterPrefix(type) + str(registerIndex) + ")";
- uniforms += "uniform " + typeName + " " + DecorateUniform(name, type) + ArrayString(type) + " : " + registerString + ";\n";
+ out << "uniform " << typeName << " " << DecorateUniform(name, type) << ArrayString(type)
+ << " : " << registerString << ";\n";
}
}
- return (uniforms.empty() ? "" : ("// Uniforms\n\n" + uniforms));
+ if (outputType == SH_HLSL_4_1_OUTPUT)
+ {
+ unsigned int groupTextureRegisterIndex = 0;
+ // TEXTURE_2D is special, index offset is assumed to be 0 and omitted in that case.
+ ASSERT(HLSL_TEXTURE_MIN == HLSL_TEXTURE_2D);
+ for (int groupId = HLSL_TEXTURE_MIN; groupId < HLSL_TEXTURE_MAX; ++groupId)
+ {
+ outputHLSLSamplerUniformGroup(out, HLSLTextureSamplerGroup(groupId),
+ groupedSamplerUniforms[groupId],
+ &groupTextureRegisterIndex);
+ }
+ }
}
TString UniformHLSL::interfaceBlocksHeader(const ReferencedSymbols &referencedInterfaceBlocks)
diff --git a/src/3rdparty/angle/src/compiler/translator/UniformHLSL.h b/src/3rdparty/angle/src/compiler/translator/UniformHLSL.h
index 4ab9ccdf53..0f51f349bb 100644
--- a/src/3rdparty/angle/src/compiler/translator/UniformHLSL.h
+++ b/src/3rdparty/angle/src/compiler/translator/UniformHLSL.h
@@ -11,6 +11,7 @@
#define COMPILER_TRANSLATOR_UNIFORMHLSL_H_
#include "compiler/translator/OutputHLSL.h"
+#include "compiler/translator/UtilsHLSL.h"
namespace sh
{
@@ -23,7 +24,13 @@ class UniformHLSL : angle::NonCopyable
void reserveUniformRegisters(unsigned int registerCount);
void reserveInterfaceBlockRegisters(unsigned int registerCount);
- TString uniformsHeader(ShShaderOutput outputType, const ReferencedSymbols &referencedUniforms);
+ void outputHLSLSamplerUniformGroup(TInfoSinkBase &out,
+ const HLSLTextureSamplerGroup textureGroup,
+ const TVector<const TIntermSymbol *> &group,
+ unsigned int *groupTextureRegisterIndex);
+ void uniformsHeader(TInfoSinkBase &out,
+ ShShaderOutput outputType,
+ const ReferencedSymbols &referencedUniforms);
TString interfaceBlocksHeader(const ReferencedSymbols &referencedInterfaceBlocks);
// Used for direct index references
@@ -45,6 +52,9 @@ class UniformHLSL : angle::NonCopyable
const Uniform *findUniformByName(const TString &name) const;
// Returns the uniform's register index
+ unsigned int declareUniformAndAssignRegister(const TType &type,
+ const TString &name,
+ unsigned int *registerCount);
unsigned int declareUniformAndAssignRegister(const TType &type, const TString &name);
unsigned int mUniformRegister;
diff --git a/src/3rdparty/angle/src/compiler/translator/UtilsHLSL.cpp b/src/3rdparty/angle/src/compiler/translator/UtilsHLSL.cpp
index 94e19ac40d..404ccee75d 100644
--- a/src/3rdparty/angle/src/compiler/translator/UtilsHLSL.cpp
+++ b/src/3rdparty/angle/src/compiler/translator/UtilsHLSL.cpp
@@ -8,15 +8,16 @@
//
#include "compiler/translator/UtilsHLSL.h"
+#include "compiler/translator/IntermNode.h"
#include "compiler/translator/StructureHLSL.h"
#include "compiler/translator/SymbolTable.h"
namespace sh
{
-TString SamplerString(const TType &type)
+TString SamplerString(const TBasicType type)
{
- if (IsShadowSampler(type.getBasicType()))
+ if (IsShadowSampler(type))
{
return "SamplerComparisonState";
}
@@ -26,32 +27,158 @@ TString SamplerString(const TType &type)
}
}
-TString TextureString(const TType &type)
+TString SamplerString(HLSLTextureSamplerGroup type)
{
- switch (type.getBasicType())
+ if (type >= HLSL_COMPARISON_SAMPLER_GROUP_BEGIN && type <= HLSL_COMPARISON_SAMPLER_GROUP_END)
{
- case EbtSampler2D: return "Texture2D";
- case EbtSamplerCube: return "TextureCube";
- case EbtSamplerExternalOES: return "Texture2D";
- case EbtSampler2DArray: return "Texture2DArray";
- case EbtSampler3D: return "Texture3D";
- case EbtISampler2D: return "Texture2D<int4>";
- case EbtISampler3D: return "Texture3D<int4>";
- case EbtISamplerCube: return "Texture2DArray<int4>";
- case EbtISampler2DArray: return "Texture2DArray<int4>";
- case EbtUSampler2D: return "Texture2D<uint4>";
- case EbtUSampler3D: return "Texture3D<uint4>";
- case EbtUSamplerCube: return "Texture2DArray<uint4>";
- case EbtUSampler2DArray: return "Texture2DArray<uint4>";
- case EbtSampler2DShadow: return "Texture2D";
- case EbtSamplerCubeShadow: return "TextureCube";
- case EbtSampler2DArrayShadow: return "Texture2DArray";
- default: UNREACHABLE();
+ return "SamplerComparisonState";
+ }
+ else
+ {
+ return "SamplerState";
+ }
+}
+
+HLSLTextureSamplerGroup TextureGroup(const TBasicType type)
+{
+ switch (type)
+ {
+ case EbtSampler2D:
+ return HLSL_TEXTURE_2D;
+ case EbtSamplerCube:
+ return HLSL_TEXTURE_CUBE;
+ case EbtSamplerExternalOES:
+ return HLSL_TEXTURE_2D;
+ case EbtSampler2DArray:
+ return HLSL_TEXTURE_2D_ARRAY;
+ case EbtSampler3D:
+ return HLSL_TEXTURE_3D;
+ case EbtISampler2D:
+ return HLSL_TEXTURE_2D_INT4;
+ case EbtISampler3D:
+ return HLSL_TEXTURE_3D_INT4;
+ case EbtISamplerCube:
+ return HLSL_TEXTURE_2D_ARRAY_INT4;
+ case EbtISampler2DArray:
+ return HLSL_TEXTURE_2D_ARRAY_INT4;
+ case EbtUSampler2D:
+ return HLSL_TEXTURE_2D_UINT4;
+ case EbtUSampler3D:
+ return HLSL_TEXTURE_3D_UINT4;
+ case EbtUSamplerCube:
+ return HLSL_TEXTURE_2D_ARRAY_UINT4;
+ case EbtUSampler2DArray:
+ return HLSL_TEXTURE_2D_ARRAY_UINT4;
+ case EbtSampler2DShadow:
+ return HLSL_TEXTURE_2D_COMPARISON;
+ case EbtSamplerCubeShadow:
+ return HLSL_TEXTURE_CUBE_COMPARISON;
+ case EbtSampler2DArrayShadow:
+ return HLSL_TEXTURE_2D_ARRAY_COMPARISON;
+ default:
+ UNREACHABLE();
+ }
+ return HLSL_TEXTURE_UNKNOWN;
+}
+
+TString TextureString(const HLSLTextureSamplerGroup type)
+{
+ switch (type)
+ {
+ case HLSL_TEXTURE_2D:
+ return "Texture2D";
+ case HLSL_TEXTURE_CUBE:
+ return "TextureCube";
+ case HLSL_TEXTURE_2D_ARRAY:
+ return "Texture2DArray";
+ case HLSL_TEXTURE_3D:
+ return "Texture3D";
+ case HLSL_TEXTURE_2D_INT4:
+ return "Texture2D<int4>";
+ case HLSL_TEXTURE_3D_INT4:
+ return "Texture3D<int4>";
+ case HLSL_TEXTURE_2D_ARRAY_INT4:
+ return "Texture2DArray<int4>";
+ case HLSL_TEXTURE_2D_UINT4:
+ return "Texture2D<uint4>";
+ case HLSL_TEXTURE_3D_UINT4:
+ return "Texture3D<uint4>";
+ case HLSL_TEXTURE_2D_ARRAY_UINT4:
+ return "Texture2DArray<uint4>";
+ case HLSL_TEXTURE_2D_COMPARISON:
+ return "Texture2D";
+ case HLSL_TEXTURE_CUBE_COMPARISON:
+ return "TextureCube";
+ case HLSL_TEXTURE_2D_ARRAY_COMPARISON:
+ return "Texture2DArray";
+ default:
+ UNREACHABLE();
}
return "<unknown texture type>";
}
+TString TextureString(const TBasicType type)
+{
+ return TextureString(TextureGroup(type));
+}
+
+TString TextureGroupSuffix(const HLSLTextureSamplerGroup type)
+{
+ switch (type)
+ {
+ case HLSL_TEXTURE_2D:
+ return "2D";
+ case HLSL_TEXTURE_CUBE:
+ return "Cube";
+ case HLSL_TEXTURE_2D_ARRAY:
+ return "2DArray";
+ case HLSL_TEXTURE_3D:
+ return "3D";
+ case HLSL_TEXTURE_2D_INT4:
+ return "2D_int4_";
+ case HLSL_TEXTURE_3D_INT4:
+ return "3D_int4_";
+ case HLSL_TEXTURE_2D_ARRAY_INT4:
+ return "2DArray_int4_";
+ case HLSL_TEXTURE_2D_UINT4:
+ return "2D_uint4_";
+ case HLSL_TEXTURE_3D_UINT4:
+ return "3D_uint4_";
+ case HLSL_TEXTURE_2D_ARRAY_UINT4:
+ return "2DArray_uint4_";
+ case HLSL_TEXTURE_2D_COMPARISON:
+ return "2D_comparison";
+ case HLSL_TEXTURE_CUBE_COMPARISON:
+ return "Cube_comparison";
+ case HLSL_TEXTURE_2D_ARRAY_COMPARISON:
+ return "2DArray_comparison";
+ default:
+ UNREACHABLE();
+ }
+
+ return "<unknown texture type>";
+}
+
+TString TextureGroupSuffix(const TBasicType type)
+{
+ return TextureGroupSuffix(TextureGroup(type));
+}
+
+TString TextureTypeSuffix(const TBasicType type)
+{
+ switch (type)
+ {
+ case EbtISamplerCube:
+ return "Cube_int4_";
+ case EbtUSamplerCube:
+ return "Cube_uint4_";
+ default:
+ // All other types are identified by their group suffix
+ return TextureGroupSuffix(type);
+ }
+}
+
TString DecorateUniform(const TString &string, const TType &type)
{
if (type.getBasicType() == EbtSamplerExternalOES)
@@ -87,6 +214,30 @@ TString Decorate(const TString &string)
return string;
}
+TString DecorateIfNeeded(const TName &name)
+{
+ if (name.isInternal())
+ {
+ return name.getString();
+ }
+ else
+ {
+ return Decorate(name.getString());
+ }
+}
+
+TString DecorateFunctionIfNeeded(const TName &name)
+{
+ if (name.isInternal())
+ {
+ return TFunction::unmangleName(name.getString());
+ }
+ else
+ {
+ return Decorate(TFunction::unmangleName(name.getString()));
+ }
+}
+
TString TypeString(const TType &type)
{
const TStructure* structure = type.getStruct();
@@ -217,13 +368,11 @@ TString InterpolationString(TQualifier qualifier)
{
case EvqVaryingIn: return "";
case EvqFragmentIn: return "";
- case EvqInvariantVaryingIn: return "";
case EvqSmoothIn: return "linear";
case EvqFlatIn: return "nointerpolation";
case EvqCentroidIn: return "centroid";
case EvqVaryingOut: return "";
case EvqVertexOut: return "";
- case EvqInvariantVaryingOut: return "";
case EvqSmoothOut: return "linear";
case EvqFlatOut: return "nointerpolation";
case EvqCentroidOut: return "centroid";
@@ -247,4 +396,43 @@ TString QualifierString(TQualifier qualifier)
return "";
}
+int HLSLTextureCoordsCount(const TBasicType samplerType)
+{
+ switch (samplerType)
+ {
+ case EbtSampler2D:
+ return 2;
+ case EbtSampler3D:
+ return 3;
+ case EbtSamplerCube:
+ return 3;
+ case EbtSampler2DArray:
+ return 3;
+ case EbtISampler2D:
+ return 2;
+ case EbtISampler3D:
+ return 3;
+ case EbtISamplerCube:
+ return 3;
+ case EbtISampler2DArray:
+ return 3;
+ case EbtUSampler2D:
+ return 2;
+ case EbtUSampler3D:
+ return 3;
+ case EbtUSamplerCube:
+ return 3;
+ case EbtUSampler2DArray:
+ return 3;
+ case EbtSampler2DShadow:
+ return 2;
+ case EbtSamplerCubeShadow:
+ return 3;
+ case EbtSampler2DArrayShadow:
+ return 3;
+ default:
+ UNREACHABLE();
+ }
+ return 0;
+}
}
diff --git a/src/3rdparty/angle/src/compiler/translator/UtilsHLSL.h b/src/3rdparty/angle/src/compiler/translator/UtilsHLSL.h
index 9800a3bbf3..42444e3a56 100644
--- a/src/3rdparty/angle/src/compiler/translator/UtilsHLSL.h
+++ b/src/3rdparty/angle/src/compiler/translator/UtilsHLSL.h
@@ -15,13 +15,54 @@
#include "angle_gl.h"
+class TName;
+
namespace sh
{
-TString TextureString(const TType &type);
-TString SamplerString(const TType &type);
+// Unique combinations of HLSL Texture type and HLSL Sampler type.
+enum HLSLTextureSamplerGroup
+{
+ // Regular samplers
+ HLSL_TEXTURE_2D,
+ HLSL_TEXTURE_MIN = HLSL_TEXTURE_2D,
+
+ HLSL_TEXTURE_CUBE,
+ HLSL_TEXTURE_2D_ARRAY,
+ HLSL_TEXTURE_3D,
+ HLSL_TEXTURE_2D_INT4,
+ HLSL_TEXTURE_3D_INT4,
+ HLSL_TEXTURE_2D_ARRAY_INT4,
+ HLSL_TEXTURE_2D_UINT4,
+ HLSL_TEXTURE_3D_UINT4,
+ HLSL_TEXTURE_2D_ARRAY_UINT4,
+
+ // Comparison samplers
+
+ HLSL_TEXTURE_2D_COMPARISON,
+ HLSL_TEXTURE_CUBE_COMPARISON,
+ HLSL_TEXTURE_2D_ARRAY_COMPARISON,
+
+ HLSL_COMPARISON_SAMPLER_GROUP_BEGIN = HLSL_TEXTURE_2D_COMPARISON,
+ HLSL_COMPARISON_SAMPLER_GROUP_END = HLSL_TEXTURE_2D_ARRAY_COMPARISON,
+
+ HLSL_TEXTURE_UNKNOWN,
+ HLSL_TEXTURE_MAX = HLSL_TEXTURE_UNKNOWN
+};
+
+HLSLTextureSamplerGroup TextureGroup(const TBasicType type);
+TString TextureString(const HLSLTextureSamplerGroup type);
+TString TextureString(const TBasicType type);
+TString TextureGroupSuffix(const HLSLTextureSamplerGroup type);
+TString TextureGroupSuffix(const TBasicType type);
+TString TextureTypeSuffix(const TBasicType type);
+TString SamplerString(const TBasicType type);
+TString SamplerString(HLSLTextureSamplerGroup type);
// Prepends an underscore to avoid naming clashes
TString Decorate(const TString &string);
+TString DecorateIfNeeded(const TName &name);
+// Decorates and also unmangles the function name
+TString DecorateFunctionIfNeeded(const TName &name);
TString DecorateUniform(const TString &string, const TType &type);
TString DecorateField(const TString &string, const TStructure &structure);
TString DecoratePrivate(const TString &privateText);
@@ -31,7 +72,7 @@ TString QualifiedStructNameString(const TStructure &structure, bool useHLSLRowMa
bool useStd140Packing);
TString InterpolationString(TQualifier qualifier);
TString QualifierString(TQualifier qualifier);
-
+int HLSLTextureCoordsCount(const TBasicType samplerType);
}
#endif // COMPILER_TRANSLATOR_UTILSHLSL_H_
diff --git a/src/3rdparty/angle/src/compiler/translator/ValidateGlobalInitializer.cpp b/src/3rdparty/angle/src/compiler/translator/ValidateGlobalInitializer.cpp
new file mode 100644
index 0000000000..2461b6a438
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/translator/ValidateGlobalInitializer.cpp
@@ -0,0 +1,112 @@
+//
+// Copyright (c) 2002-2015 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/ValidateGlobalInitializer.h"
+
+#include "compiler/translator/ParseContext.h"
+
+namespace
+{
+
+class ValidateGlobalInitializerTraverser : public TIntermTraverser
+{
+ public:
+ ValidateGlobalInitializerTraverser(const TParseContext *context);
+
+ void visitSymbol(TIntermSymbol *node) override;
+ bool visitAggregate(Visit visit, TIntermAggregate *node) override;
+ bool visitBinary(Visit visit, TIntermBinary *node) override;
+ bool visitUnary(Visit visit, TIntermUnary *node) override;
+
+ bool isValid() const { return mIsValid; }
+ bool issueWarning() const { return mIssueWarning; }
+
+ private:
+ const TParseContext *mContext;
+ bool mIsValid;
+ bool mIssueWarning;
+};
+
+void ValidateGlobalInitializerTraverser::visitSymbol(TIntermSymbol *node)
+{
+ const TSymbol *sym = mContext->symbolTable.find(node->getSymbol(), mContext->getShaderVersion());
+ if (sym->isVariable())
+ {
+ // ESSL 1.00 section 4.3 (or ESSL 3.00 section 4.3):
+ // Global initializers must be constant expressions.
+ const TVariable *var = static_cast<const TVariable *>(sym);
+ switch (var->getType().getQualifier())
+ {
+ case EvqConst:
+ break;
+ case EvqGlobal:
+ case EvqTemporary:
+ case EvqUniform:
+ // We allow these cases to be compatible with legacy ESSL 1.00 content.
+ // Implement stricter rules for ESSL 3.00 since there's no legacy content to deal with.
+ if (mContext->getShaderVersion() >= 300)
+ {
+ mIsValid = false;
+ }
+ else
+ {
+ mIssueWarning = true;
+ }
+ break;
+ default:
+ mIsValid = false;
+ }
+ }
+}
+
+bool ValidateGlobalInitializerTraverser::visitAggregate(Visit visit, TIntermAggregate *node)
+{
+ // Disallow calls to user-defined functions and texture lookup functions in global variable initializers.
+ // This is done simply by disabling all function calls - built-in math functions don't use EOpFunctionCall.
+ if (node->getOp() == EOpFunctionCall)
+ {
+ mIsValid = false;
+ }
+ return true;
+}
+
+bool ValidateGlobalInitializerTraverser::visitBinary(Visit visit, TIntermBinary *node)
+{
+ if (node->isAssignment())
+ {
+ mIsValid = false;
+ }
+ return true;
+}
+
+bool ValidateGlobalInitializerTraverser::visitUnary(Visit visit, TIntermUnary *node)
+{
+ if (node->isAssignment())
+ {
+ mIsValid = false;
+ }
+ return true;
+}
+
+ValidateGlobalInitializerTraverser::ValidateGlobalInitializerTraverser(const TParseContext *context)
+ : TIntermTraverser(true, false, false),
+ mContext(context),
+ mIsValid(true),
+ mIssueWarning(false)
+{
+}
+
+} // namespace
+
+bool ValidateGlobalInitializer(TIntermTyped *initializer, const TParseContext *context, bool *warning)
+{
+ ValidateGlobalInitializerTraverser validate(context);
+ initializer->traverse(&validate);
+ ASSERT(warning != nullptr);
+ *warning = validate.issueWarning();
+ return validate.isValid();
+}
+
diff --git a/src/3rdparty/angle/src/compiler/translator/ValidateGlobalInitializer.h b/src/3rdparty/angle/src/compiler/translator/ValidateGlobalInitializer.h
new file mode 100644
index 0000000000..c3d2a47eba
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/translator/ValidateGlobalInitializer.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.
+//
+
+#ifndef COMPILER_TRANSLATOR_VALIDATEGLOBALINITIALIZER_H_
+#define COMPILER_TRANSLATOR_VALIDATEGLOBALINITIALIZER_H_
+
+class TIntermTyped;
+class TParseContext;
+
+// Returns true if the initializer is valid.
+bool ValidateGlobalInitializer(TIntermTyped *initializer, const TParseContext *context, bool *warning);
+
+#endif // COMPILER_TRANSLATOR_VALIDATEGLOBALINITIALIZER_H_
diff --git a/src/3rdparty/angle/src/compiler/translator/ValidateLimitations.cpp b/src/3rdparty/angle/src/compiler/translator/ValidateLimitations.cpp
index 12367066e8..ba8cdd0aa8 100644
--- a/src/3rdparty/angle/src/compiler/translator/ValidateLimitations.cpp
+++ b/src/3rdparty/angle/src/compiler/translator/ValidateLimitations.cpp
@@ -26,12 +26,16 @@ class ValidateConstIndexExpr : public TIntermTraverser
{
public:
ValidateConstIndexExpr(TLoopStack& stack)
- : mValid(true), mLoopStack(stack) {}
+ : TIntermTraverser(true, false, false),
+ mValid(true),
+ mLoopStack(stack)
+ {
+ }
// Returns true if the parsed node represents a constant index expression.
bool isValid() const { return mValid; }
- virtual void visitSymbol(TIntermSymbol *symbol)
+ void visitSymbol(TIntermSymbol *symbol) override
{
// Only constants and loop indices are allowed in a
// constant index expression.
@@ -49,12 +53,35 @@ class ValidateConstIndexExpr : public TIntermTraverser
} // namespace anonymous
-ValidateLimitations::ValidateLimitations(sh::GLenum shaderType,
- TInfoSinkBase &sink)
- : mShaderType(shaderType),
+ValidateLimitations::ValidateLimitations(sh::GLenum shaderType, TInfoSinkBase *sink)
+ : TIntermTraverser(true, false, false),
+ mShaderType(shaderType),
mSink(sink),
- mNumErrors(0)
+ mNumErrors(0),
+ mValidateIndexing(true),
+ mValidateInnerLoops(true)
+{
+}
+
+// static
+bool ValidateLimitations::IsLimitedForLoop(TIntermLoop *loop)
{
+ // The shader type doesn't matter in this case.
+ ValidateLimitations validate(GL_FRAGMENT_SHADER, nullptr);
+ validate.mValidateIndexing = false;
+ validate.mValidateInnerLoops = false;
+ if (!validate.validateLoopType(loop))
+ return false;
+ if (!validate.validateForLoopHeader(loop))
+ return false;
+ TIntermNode *body = loop->getBody();
+ if (body != nullptr)
+ {
+ validate.mLoopStack.push(loop);
+ body->traverse(&validate);
+ validate.mLoopStack.pop();
+ }
+ return (validate.mNumErrors == 0);
}
bool ValidateLimitations::visitBinary(Visit, TIntermBinary *node)
@@ -67,10 +94,11 @@ bool ValidateLimitations::visitBinary(Visit, TIntermBinary *node)
{
case EOpIndexDirect:
case EOpIndexIndirect:
- validateIndexing(node);
- break;
+ if (mValidateIndexing)
+ validateIndexing(node);
+ break;
default:
- break;
+ break;
}
return true;
}
@@ -97,6 +125,9 @@ bool ValidateLimitations::visitAggregate(Visit, TIntermAggregate *node)
bool ValidateLimitations::visitLoop(Visit, TIntermLoop *node)
{
+ if (!mValidateInnerLoops)
+ return true;
+
if (!validateLoopType(node))
return false;
@@ -118,9 +149,12 @@ bool ValidateLimitations::visitLoop(Visit, TIntermLoop *node)
void ValidateLimitations::error(TSourceLoc loc,
const char *reason, const char *token)
{
- mSink.prefix(EPrefixError);
- mSink.location(loc);
- mSink << "'" << token << "' : " << reason << "\n";
+ if (mSink)
+ {
+ mSink->prefix(EPrefixError);
+ mSink->location(loc);
+ (*mSink) << "'" << token << "' : " << reason << "\n";
+ }
++mNumErrors;
}
@@ -389,13 +423,13 @@ bool ValidateLimitations::validateFunctionCall(TIntermAggregate *node)
bool valid = true;
TSymbolTable& symbolTable = GetGlobalParseContext()->symbolTable;
- TSymbol* symbol = symbolTable.find(node->getName(), GetGlobalParseContext()->shaderVersion);
+ TSymbol* symbol = symbolTable.find(node->getName(), GetGlobalParseContext()->getShaderVersion());
ASSERT(symbol && symbol->isFunction());
TFunction *function = static_cast<TFunction *>(symbol);
for (ParamIndex::const_iterator i = pIndex.begin();
i != pIndex.end(); ++i)
{
- const TParameter &param = function->getParam(*i);
+ const TConstParameter &param = function->getParam(*i);
TQualifier qual = param.type->getQualifier();
if ((qual == EvqOut) || (qual == EvqInOut))
{
@@ -428,8 +462,8 @@ bool ValidateLimitations::validateOperation(TIntermOperator *node,
bool ValidateLimitations::isConstExpr(TIntermNode *node)
{
- ASSERT(node != NULL);
- return node->getAsConstantUnion() != NULL;
+ ASSERT(node != nullptr);
+ return node->getAsConstantUnion() != nullptr && node->getAsTyped()->getQualifier() == EvqConst;
}
bool ValidateLimitations::isConstIndexExpr(TIntermNode *node)
@@ -448,13 +482,6 @@ bool ValidateLimitations::validateIndexing(TIntermBinary *node)
bool valid = true;
TIntermTyped *index = node->getRight();
- // The index expression must have integral type.
- if (!index->isScalarInt()) {
- error(index->getLine(),
- "Index expression must have integral type",
- index->getCompleteString().c_str());
- valid = false;
- }
// The index expession must be a constant-index-expression unless
// the operand is a uniform in a vertex shader.
TIntermTyped *operand = node->getLeft();
diff --git a/src/3rdparty/angle/src/compiler/translator/ValidateLimitations.h b/src/3rdparty/angle/src/compiler/translator/ValidateLimitations.h
index 59cccb565f..666e38ff5c 100644
--- a/src/3rdparty/angle/src/compiler/translator/ValidateLimitations.h
+++ b/src/3rdparty/angle/src/compiler/translator/ValidateLimitations.h
@@ -17,14 +17,16 @@ class TInfoSinkBase;
class ValidateLimitations : public TIntermTraverser
{
public:
- ValidateLimitations(sh::GLenum shaderType, TInfoSinkBase &sink);
+ ValidateLimitations(sh::GLenum shaderType, TInfoSinkBase *sink);
int numErrors() const { return mNumErrors; }
- virtual bool visitBinary(Visit, TIntermBinary *);
- virtual bool visitUnary(Visit, TIntermUnary *);
- virtual bool visitAggregate(Visit, TIntermAggregate *);
- virtual bool visitLoop(Visit, TIntermLoop *);
+ bool visitBinary(Visit, TIntermBinary *) override;
+ bool visitUnary(Visit, TIntermUnary *) override;
+ bool visitAggregate(Visit, TIntermAggregate *) override;
+ bool visitLoop(Visit, TIntermLoop *) override;
+
+ static bool IsLimitedForLoop(TIntermLoop *node);
private:
void error(TSourceLoc loc, const char *reason, const char *token);
@@ -51,9 +53,11 @@ class ValidateLimitations : public TIntermTraverser
bool validateIndexing(TIntermBinary *node);
sh::GLenum mShaderType;
- TInfoSinkBase &mSink;
+ TInfoSinkBase *mSink;
int mNumErrors;
TLoopStack mLoopStack;
+ bool mValidateIndexing;
+ bool mValidateInnerLoops;
};
#endif // COMPILER_TRANSLATOR_VALIDATELIMITATIONS_H_
diff --git a/src/3rdparty/angle/src/compiler/translator/ValidateOutputs.cpp b/src/3rdparty/angle/src/compiler/translator/ValidateOutputs.cpp
index ac1c10d6b0..cd37aeacd1 100644
--- a/src/3rdparty/angle/src/compiler/translator/ValidateOutputs.cpp
+++ b/src/3rdparty/angle/src/compiler/translator/ValidateOutputs.cpp
@@ -9,11 +9,23 @@
#include "compiler/translator/InitializeParseContext.h"
#include "compiler/translator/ParseContext.h"
-ValidateOutputs::ValidateOutputs(TInfoSinkBase& sink, int maxDrawBuffers)
- : mSink(sink),
+namespace
+{
+void error(int *errorCount, TInfoSinkBase &sink, const TIntermSymbol &symbol, const char *reason)
+{
+ sink.prefix(EPrefixError);
+ sink.location(symbol.getLine());
+ sink << "'" << symbol.getSymbol() << "' : " << reason << "\n";
+ (*errorCount)++;
+}
+
+} // namespace
+
+ValidateOutputs::ValidateOutputs(const TExtensionBehavior &extBehavior, int maxDrawBuffers)
+ : TIntermTraverser(true, false, false),
mMaxDrawBuffers(maxDrawBuffers),
- mNumErrors(0),
- mHasUnspecifiedOutputLocation(false)
+ mAllowUnspecifiedOutputLocationResolution(
+ IsExtensionEnabled(extBehavior, "GL_EXT_blend_func_extended"))
{
}
@@ -29,50 +41,68 @@ void ValidateOutputs::visitSymbol(TIntermSymbol *symbol)
if (qualifier == EvqFragmentOut)
{
- const TType &type = symbol->getType();
- const int location = type.getLayoutQualifier().location;
-
- if (mHasUnspecifiedOutputLocation)
+ if (symbol->getType().getLayoutQualifier().location == -1)
{
- error(symbol->getLine(), "must explicitly specify all locations when using multiple fragment outputs", name.c_str());
+ mUnspecifiedLocationOutputs.push_back(symbol);
}
- else if (location == -1)
+ else
{
- mHasUnspecifiedOutputLocation = true;
+ mOutputs.push_back(symbol);
}
- else
+ }
+}
+
+int ValidateOutputs::validateAndCountErrors(TInfoSinkBase &sink) const
+{
+ OutputVector validOutputs(mMaxDrawBuffers);
+ int errorCount = 0;
+
+ for (const auto &symbol : mOutputs)
+ {
+ const TType &type = symbol->getType();
+ const size_t elementCount = static_cast<size_t>(type.isArray() ? type.getArraySize() : 1);
+ const size_t location = static_cast<size_t>(type.getLayoutQualifier().location);
+
+ ASSERT(type.getLayoutQualifier().location != -1);
+
+ if (location + elementCount <= validOutputs.size())
{
- OutputMap::iterator mapEntry = mOutputMap.find(location);
- if (mapEntry == mOutputMap.end())
+ for (size_t elementIndex = 0; elementIndex < elementCount; elementIndex++)
{
- const int elementCount = type.isArray() ? type.getArraySize() : 1;
- if (location + elementCount > mMaxDrawBuffers)
+ const size_t offsetLocation = location + elementIndex;
+ if (validOutputs[offsetLocation])
{
- error(symbol->getLine(), "output location must be < MAX_DRAW_BUFFERS", name.c_str());
+ std::stringstream strstr;
+ strstr << "conflicting output locations with previously defined output '"
+ << validOutputs[offsetLocation]->getSymbol() << "'";
+ error(&errorCount, sink, *symbol, strstr.str().c_str());
}
-
- for (int elementIndex = 0; elementIndex < elementCount; elementIndex++)
+ else
{
- const int offsetLocation = location + elementIndex;
- mOutputMap[offsetLocation] = symbol;
+ validOutputs[offsetLocation] = symbol;
}
}
- else
+ }
+ else
+ {
+ if (elementCount > 0)
{
- std::stringstream strstr;
- strstr << "conflicting output locations with previously defined output '"
- << mapEntry->second->getSymbol() << "'";
-
- error(symbol->getLine(), strstr.str().c_str(), name.c_str());
+ error(&errorCount, sink, *symbol,
+ elementCount > 1 ? "output array locations would exceed MAX_DRAW_BUFFERS"
+ : "output location must be < MAX_DRAW_BUFFERS");
}
}
}
-}
-void ValidateOutputs::error(TSourceLoc loc, const char *reason, const char* token)
-{
- mSink.prefix(EPrefixError);
- mSink.location(loc);
- mSink << "'" << token << "' : " << reason << "\n";
- mNumErrors++;
+ if (!mAllowUnspecifiedOutputLocationResolution &&
+ ((!mOutputs.empty() && !mUnspecifiedLocationOutputs.empty()) ||
+ mUnspecifiedLocationOutputs.size() > 1))
+ {
+ for (const auto &symbol : mUnspecifiedLocationOutputs)
+ {
+ error(&errorCount, sink, *symbol,
+ "must explicitly specify all locations when using multiple fragment outputs");
+ }
+ }
+ return errorCount;
}
diff --git a/src/3rdparty/angle/src/compiler/translator/ValidateOutputs.h b/src/3rdparty/angle/src/compiler/translator/ValidateOutputs.h
index 1538e0f157..06f63994cd 100644
--- a/src/3rdparty/angle/src/compiler/translator/ValidateOutputs.h
+++ b/src/3rdparty/angle/src/compiler/translator/ValidateOutputs.h
@@ -7,6 +7,7 @@
#ifndef COMPILER_TRANSLATOR_VALIDATEOUTPUTS_H_
#define COMPILER_TRANSLATOR_VALIDATEOUTPUTS_H_
+#include "compiler/translator/ExtensionBehavior.h"
#include "compiler/translator/IntermNode.h"
#include <set>
@@ -16,23 +17,20 @@ class TInfoSinkBase;
class ValidateOutputs : public TIntermTraverser
{
public:
- ValidateOutputs(TInfoSinkBase& sink, int maxDrawBuffers);
+ ValidateOutputs(const TExtensionBehavior &extBehavior, int maxDrawBuffers);
- int numErrors() const { return mNumErrors; }
+ int validateAndCountErrors(TInfoSinkBase &sink) const;
- virtual void visitSymbol(TIntermSymbol*);
+ void visitSymbol(TIntermSymbol *) override;
private:
- TInfoSinkBase& mSink;
int mMaxDrawBuffers;
- int mNumErrors;
- bool mHasUnspecifiedOutputLocation;
+ bool mAllowUnspecifiedOutputLocationResolution;
- typedef std::map<int, TIntermSymbol*> OutputMap;
- OutputMap mOutputMap;
+ typedef std::vector<TIntermSymbol *> OutputVector;
+ OutputVector mOutputs;
+ OutputVector mUnspecifiedLocationOutputs;
std::set<TString> mVisitedSymbols;
-
- void error(TSourceLoc loc, const char *reason, const char* token);
};
#endif // COMPILER_TRANSLATOR_VALIDATEOUTPUTS_H_
diff --git a/src/3rdparty/angle/src/compiler/translator/ValidateSwitch.h b/src/3rdparty/angle/src/compiler/translator/ValidateSwitch.h
index 88b68a500e..ddbefc5619 100644
--- a/src/3rdparty/angle/src/compiler/translator/ValidateSwitch.h
+++ b/src/3rdparty/angle/src/compiler/translator/ValidateSwitch.h
@@ -9,7 +9,7 @@
#include "compiler/translator/IntermNode.h"
-struct TParseContext;
+class TParseContext;
class ValidateSwitch : public TIntermTraverser
{
diff --git a/src/3rdparty/angle/src/compiler/translator/VariableInfo.cpp b/src/3rdparty/angle/src/compiler/translator/VariableInfo.cpp
index cf229ec96a..3b6aa6a68e 100644
--- a/src/3rdparty/angle/src/compiler/translator/VariableInfo.cpp
+++ b/src/3rdparty/angle/src/compiler/translator/VariableInfo.cpp
@@ -16,18 +16,6 @@ namespace sh
namespace
{
-TString InterfaceBlockFieldName(const TInterfaceBlock &interfaceBlock, const TField &field)
-{
- if (interfaceBlock.hasInstanceName())
- {
- return interfaceBlock.name() + "." + field.name();
- }
- else
- {
- return field.name();
- }
-}
-
BlockLayoutType GetBlockLayoutType(TLayoutBlockStorage blockStorage)
{
switch (blockStorage)
@@ -55,7 +43,8 @@ void ExpandVariable(const ShaderVariable &variable,
{
if (variable.isArray())
{
- for (size_t elementIndex = 0; elementIndex < variable.elementCount(); elementIndex++)
+ for (unsigned int elementIndex = 0; elementIndex < variable.elementCount();
+ elementIndex++)
{
std::string lname = name + ::ArrayString(elementIndex);
std::string lmappedName = mappedName + ::ArrayString(elementIndex);
@@ -128,17 +117,19 @@ VarT *FindVariable(const TString &name,
}
CollectVariables::CollectVariables(std::vector<sh::Attribute> *attribs,
- std::vector<sh::Attribute> *outputVariables,
+ std::vector<sh::OutputVariable> *outputVariables,
std::vector<sh::Uniform> *uniforms,
std::vector<sh::Varying> *varyings,
std::vector<sh::InterfaceBlock> *interfaceBlocks,
ShHashFunction64 hashFunction,
const TSymbolTable &symbolTable)
- : mAttribs(attribs),
+ : TIntermTraverser(true, false, false),
+ mAttribs(attribs),
mOutputVariables(outputVariables),
mUniforms(uniforms),
mVaryings(varyings),
mInterfaceBlocks(interfaceBlocks),
+ mDepthRangeAdded(false),
mPointCoordAdded(false),
mFrontFacingAdded(false),
mFragCoordAdded(false),
@@ -146,6 +137,12 @@ CollectVariables::CollectVariables(std::vector<sh::Attribute> *attribs,
mPositionAdded(false),
mPointSizeAdded(false),
mLastFragDataAdded(false),
+ mFragColorAdded(false),
+ mFragDataAdded(false),
+ mFragDepthEXTAdded(false),
+ mFragDepthAdded(false),
+ mSecondaryFragColorEXTAdded(false),
+ mSecondaryFragDataEXTAdded(false),
mHashFunction(hashFunction),
mSymbolTable(symbolTable)
{
@@ -170,6 +167,56 @@ void CollectVariables::visitSymbol(TIntermSymbol *symbol)
{
UNREACHABLE();
}
+ else if (symbolName == "gl_DepthRange")
+ {
+ ASSERT(symbol->getQualifier() == EvqUniform);
+
+ if (!mDepthRangeAdded)
+ {
+ Uniform info;
+ const char kName[] = "gl_DepthRange";
+ info.name = kName;
+ info.mappedName = kName;
+ info.type = GL_STRUCT_ANGLEX;
+ info.arraySize = 0;
+ info.precision = GL_NONE;
+ info.staticUse = true;
+
+ ShaderVariable nearInfo;
+ const char kNearName[] = "near";
+ nearInfo.name = kNearName;
+ nearInfo.mappedName = kNearName;
+ nearInfo.type = GL_FLOAT;
+ nearInfo.arraySize = 0;
+ nearInfo.precision = GL_HIGH_FLOAT;
+ nearInfo.staticUse = true;
+
+ ShaderVariable farInfo;
+ const char kFarName[] = "far";
+ farInfo.name = kFarName;
+ farInfo.mappedName = kFarName;
+ farInfo.type = GL_FLOAT;
+ farInfo.arraySize = 0;
+ farInfo.precision = GL_HIGH_FLOAT;
+ farInfo.staticUse = true;
+
+ ShaderVariable diffInfo;
+ const char kDiffName[] = "diff";
+ diffInfo.name = kDiffName;
+ diffInfo.mappedName = kDiffName;
+ diffInfo.type = GL_FLOAT;
+ diffInfo.arraySize = 0;
+ diffInfo.precision = GL_HIGH_FLOAT;
+ diffInfo.staticUse = true;
+
+ info.fields.push_back(nearInfo);
+ info.fields.push_back(farInfo);
+ info.fields.push_back(diffInfo);
+
+ mUniforms->push_back(info);
+ mDepthRangeAdded = true;
+ }
+ }
else
{
switch (symbol->getQualifier())
@@ -192,7 +239,6 @@ void CollectVariables::visitSymbol(TIntermSymbol *symbol)
// Set static use on the parent interface block here
namedBlock->staticUse = true;
-
}
else
{
@@ -200,7 +246,7 @@ void CollectVariables::visitSymbol(TIntermSymbol *symbol)
}
// It's an internal error to reference an undefined user uniform
- ASSERT(symbolName.compare(0, 3, "gl_") == 0 || var);
+ ASSERT(symbolName.compare(0, 3, "gl_") != 0 || var);
}
break;
case EvqFragCoord:
@@ -315,6 +361,105 @@ void CollectVariables::visitSymbol(TIntermSymbol *symbol)
mLastFragDataAdded = true;
}
return;
+ case EvqFragColor:
+ if (!mFragColorAdded)
+ {
+ OutputVariable info;
+ const char kName[] = "gl_FragColor";
+ info.name = kName;
+ info.mappedName = kName;
+ info.type = GL_FLOAT_VEC4;
+ info.arraySize = 0;
+ info.precision = GL_MEDIUM_FLOAT; // Defined by spec.
+ info.staticUse = true;
+ mOutputVariables->push_back(info);
+ mFragColorAdded = true;
+ }
+ return;
+ case EvqFragData:
+ if (!mFragDataAdded)
+ {
+ OutputVariable info;
+ const char kName[] = "gl_FragData";
+ info.name = kName;
+ info.mappedName = kName;
+ info.type = GL_FLOAT_VEC4;
+ info.arraySize = static_cast<const TVariable *>(
+ mSymbolTable.findBuiltIn("gl_MaxDrawBuffers", 100))
+ ->getConstPointer()
+ ->getIConst();
+ info.precision = GL_MEDIUM_FLOAT; // Defined by spec.
+ info.staticUse = true;
+ mOutputVariables->push_back(info);
+ mFragDataAdded = true;
+ }
+ return;
+ case EvqFragDepthEXT:
+ if (!mFragDepthEXTAdded)
+ {
+ OutputVariable info;
+ const char kName[] = "gl_FragDepthEXT";
+ info.name = kName;
+ info.mappedName = kName;
+ info.type = GL_FLOAT;
+ info.arraySize = 0;
+ info.precision =
+ GLVariablePrecision(static_cast<const TVariable *>(
+ mSymbolTable.findBuiltIn("gl_FragDepthEXT", 100))
+ ->getType());
+ info.staticUse = true;
+ mOutputVariables->push_back(info);
+ mFragDepthEXTAdded = true;
+ }
+ return;
+ case EvqFragDepth:
+ if (!mFragDepthAdded)
+ {
+ OutputVariable info;
+ const char kName[] = "gl_FragDepth";
+ info.name = kName;
+ info.mappedName = kName;
+ info.type = GL_FLOAT;
+ info.arraySize = 0;
+ info.precision = GL_HIGH_FLOAT;
+ info.staticUse = true;
+ mOutputVariables->push_back(info);
+ mFragDepthAdded = true;
+ }
+ return;
+ case EvqSecondaryFragColorEXT:
+ if (!mSecondaryFragColorEXTAdded)
+ {
+ OutputVariable info;
+ const char kName[] = "gl_SecondaryFragColorEXT";
+ info.name = kName;
+ info.mappedName = kName;
+ info.type = GL_FLOAT_VEC4;
+ info.arraySize = 0;
+ info.precision = GL_MEDIUM_FLOAT; // Defined by spec.
+ info.staticUse = true;
+ mOutputVariables->push_back(info);
+ mSecondaryFragColorEXTAdded = true;
+ }
+ return;
+ case EvqSecondaryFragDataEXT:
+ if (!mSecondaryFragDataEXTAdded)
+ {
+ OutputVariable info;
+ const char kName[] = "gl_SecondaryFragDataEXT";
+ info.name = kName;
+ info.mappedName = kName;
+ info.type = GL_FLOAT_VEC4;
+
+ const TVariable *maxDualSourceDrawBuffersVar = static_cast<const TVariable *>(
+ mSymbolTable.findBuiltIn("gl_MaxDualSourceDrawBuffersEXT", 100));
+ info.arraySize = maxDualSourceDrawBuffersVar->getConstPointer()->getIConst();
+ info.precision = GL_MEDIUM_FLOAT; // Defined by spec.
+ info.staticUse = true;
+ mOutputVariables->push_back(info);
+ mSecondaryFragDataEXTAdded = true;
+ }
+ return;
default:
break;
}
@@ -335,7 +480,7 @@ class NameHashingTraverser : public GetVariableTraverser
{}
private:
- virtual void visitVariable(ShaderVariable *variable)
+ void visitVariable(ShaderVariable *variable) override
{
TString stringName = TString(variable->name.c_str());
variable->mappedName = TIntermTraverser::hash(stringName, mHashFunction).c_str();
@@ -367,6 +512,26 @@ void CollectVariables::visitVariable(const TIntermSymbol *variable,
template <>
void CollectVariables::visitVariable(const TIntermSymbol *variable,
+ std::vector<OutputVariable> *infoList) const
+{
+ ASSERT(variable);
+ const TType &type = variable->getType();
+ ASSERT(!type.getStruct());
+
+ OutputVariable attribute;
+
+ attribute.type = GLVariableType(type);
+ attribute.precision = GLVariablePrecision(type);
+ attribute.name = variable->getSymbol().c_str();
+ attribute.arraySize = static_cast<unsigned int>(type.getArraySize());
+ attribute.mappedName = TIntermTraverser::hash(variable->getSymbol(), mHashFunction).c_str();
+ attribute.location = variable->getType().getLayoutQualifier().location;
+
+ infoList->push_back(attribute);
+}
+
+template <>
+void CollectVariables::visitVariable(const TIntermSymbol *variable,
std::vector<InterfaceBlock> *infoList) const
{
InterfaceBlock interfaceBlock;
@@ -374,23 +539,20 @@ void CollectVariables::visitVariable(const TIntermSymbol *variable,
ASSERT(blockType);
interfaceBlock.name = blockType->name().c_str();
- interfaceBlock.mappedName = TIntermTraverser::hash(variable->getSymbol(), mHashFunction).c_str();
+ interfaceBlock.mappedName =
+ TIntermTraverser::hash(blockType->name().c_str(), mHashFunction).c_str();
interfaceBlock.instanceName = (blockType->hasInstanceName() ? blockType->instanceName().c_str() : "");
interfaceBlock.arraySize = variable->getArraySize();
interfaceBlock.isRowMajorLayout = (blockType->matrixPacking() == EmpRowMajor);
interfaceBlock.layout = GetBlockLayoutType(blockType->blockStorage());
// Gather field information
- const TFieldList &fieldList = blockType->fields();
-
- for (size_t fieldIndex = 0; fieldIndex < fieldList.size(); ++fieldIndex)
+ for (const TField *field : blockType->fields())
{
- const TField &field = *fieldList[fieldIndex];
- const TString &fullFieldName = InterfaceBlockFieldName(*blockType, field);
- const TType &fieldType = *field.type();
+ const TType &fieldType = *field->type();
- GetVariableTraverser traverser(mSymbolTable);
- traverser.traverse(fieldType, fullFieldName, &interfaceBlock.fields);
+ NameHashingTraverser traverser(mHashFunction, mSymbolTable);
+ traverser.traverse(fieldType, field->name(), &interfaceBlock.fields);
interfaceBlock.fields.back().isRowMajorLayout = (fieldType.getLayoutQualifier().matrixPacking == EmpRowMajor);
}
diff --git a/src/3rdparty/angle/src/compiler/translator/VariableInfo.h b/src/3rdparty/angle/src/compiler/translator/VariableInfo.h
index bb1328a507..9498e9b3a0 100644
--- a/src/3rdparty/angle/src/compiler/translator/VariableInfo.h
+++ b/src/3rdparty/angle/src/compiler/translator/VariableInfo.h
@@ -21,16 +21,16 @@ class CollectVariables : public TIntermTraverser
{
public:
CollectVariables(std::vector<Attribute> *attribs,
- std::vector<Attribute> *outputVariables,
+ std::vector<OutputVariable> *outputVariables,
std::vector<Uniform> *uniforms,
std::vector<Varying> *varyings,
std::vector<InterfaceBlock> *interfaceBlocks,
ShHashFunction64 hashFunction,
const TSymbolTable &symbolTable);
- virtual void visitSymbol(TIntermSymbol *symbol);
- virtual bool visitAggregate(Visit, TIntermAggregate *node);
- virtual bool visitBinary(Visit visit, TIntermBinary *binaryNode);
+ void visitSymbol(TIntermSymbol *symbol) override;
+ bool visitAggregate(Visit, TIntermAggregate *node) override;
+ bool visitBinary(Visit visit, TIntermBinary *binaryNode) override;
private:
template <typename VarT>
@@ -40,13 +40,14 @@ class CollectVariables : public TIntermTraverser
void visitInfoList(const TIntermSequence &sequence, std::vector<VarT> *infoList) const;
std::vector<Attribute> *mAttribs;
- std::vector<Attribute> *mOutputVariables;
+ std::vector<OutputVariable> *mOutputVariables;
std::vector<Uniform> *mUniforms;
std::vector<Varying> *mVaryings;
std::vector<InterfaceBlock> *mInterfaceBlocks;
std::map<std::string, InterfaceBlockField *> mInterfaceBlockFields;
+ bool mDepthRangeAdded;
bool mPointCoordAdded;
bool mFrontFacingAdded;
bool mFragCoordAdded;
@@ -55,6 +56,12 @@ class CollectVariables : public TIntermTraverser
bool mPositionAdded;
bool mPointSizeAdded;
bool mLastFragDataAdded;
+ bool mFragColorAdded;
+ bool mFragDataAdded;
+ bool mFragDepthEXTAdded;
+ bool mFragDepthAdded;
+ bool mSecondaryFragColorEXTAdded;
+ bool mSecondaryFragDataEXTAdded;
ShHashFunction64 mHashFunction;
diff --git a/src/3rdparty/angle/src/compiler/translator/VersionGLSL.cpp b/src/3rdparty/angle/src/compiler/translator/VersionGLSL.cpp
index f6f568897d..c8718daa10 100644
--- a/src/3rdparty/angle/src/compiler/translator/VersionGLSL.cpp
+++ b/src/3rdparty/angle/src/compiler/translator/VersionGLSL.cpp
@@ -6,9 +6,24 @@
#include "compiler/translator/VersionGLSL.h"
-static const int GLSL_VERSION_110 = 110;
-static const int GLSL_VERSION_120 = 120;
-static const int GLSL_VERSION_150 = 150;
+int ShaderOutputTypeToGLSLVersion(ShShaderOutput output)
+{
+ switch (output)
+ {
+ case SH_GLSL_130_OUTPUT: return GLSL_VERSION_130;
+ case SH_GLSL_140_OUTPUT: return GLSL_VERSION_140;
+ case SH_GLSL_150_CORE_OUTPUT: return GLSL_VERSION_150;
+ case SH_GLSL_330_CORE_OUTPUT: return GLSL_VERSION_330;
+ case SH_GLSL_400_CORE_OUTPUT: return GLSL_VERSION_400;
+ case SH_GLSL_410_CORE_OUTPUT: return GLSL_VERSION_410;
+ case SH_GLSL_420_CORE_OUTPUT: return GLSL_VERSION_420;
+ case SH_GLSL_430_CORE_OUTPUT: return GLSL_VERSION_430;
+ case SH_GLSL_440_CORE_OUTPUT: return GLSL_VERSION_440;
+ case SH_GLSL_450_CORE_OUTPUT: return GLSL_VERSION_450;
+ case SH_GLSL_COMPATIBILITY_OUTPUT: return GLSL_VERSION_110;
+ default: UNREACHABLE(); return 0;
+ }
+}
// We need to scan for the following:
// 1. "invariant" keyword: This can occur in both - vertex and fragment shaders
@@ -30,25 +45,21 @@ static const int GLSL_VERSION_150 = 150;
TVersionGLSL::TVersionGLSL(sh::GLenum type,
const TPragma &pragma,
ShShaderOutput output)
+ : TIntermTraverser(true, false, false)
{
- if (output == SH_GLSL_CORE_OUTPUT)
+ mVersion = ShaderOutputTypeToGLSLVersion(output);
+ if (pragma.stdgl.invariantAll)
{
- mVersion = GLSL_VERSION_150;
- }
- else
- {
- ASSERT(output == SH_GLSL_COMPATIBILITY_OUTPUT);
- if (pragma.stdgl.invariantAll)
- mVersion = GLSL_VERSION_120;
- else
- mVersion = GLSL_VERSION_110;
+ ensureVersionIsAtLeast(GLSL_VERSION_120);
}
}
void TVersionGLSL::visitSymbol(TIntermSymbol *node)
{
if (node->getSymbol() == "gl_PointCoord")
- updateVersion(GLSL_VERSION_120);
+ {
+ ensureVersionIsAtLeast(GLSL_VERSION_120);
+ }
}
bool TVersionGLSL::visitAggregate(Visit, TIntermAggregate *node)
@@ -64,16 +75,14 @@ bool TVersionGLSL::visitAggregate(Visit, TIntermAggregate *node)
case EOpDeclaration:
{
const TIntermSequence &sequence = *(node->getSequence());
- TQualifier qualifier = sequence.front()->getAsTyped()->getQualifier();
- if ((qualifier == EvqInvariantVaryingIn) ||
- (qualifier == EvqInvariantVaryingOut))
+ if (sequence.front()->getAsTyped()->getType().isInvariant())
{
- updateVersion(GLSL_VERSION_120);
+ ensureVersionIsAtLeast(GLSL_VERSION_120);
}
break;
}
case EOpInvariantDeclaration:
- updateVersion(GLSL_VERSION_120);
+ ensureVersionIsAtLeast(GLSL_VERSION_120);
break;
case EOpParameters:
{
@@ -87,7 +96,7 @@ bool TVersionGLSL::visitAggregate(Visit, TIntermAggregate *node)
TQualifier qualifier = param->getQualifier();
if ((qualifier == EvqOut) || (qualifier == EvqInOut))
{
- updateVersion(GLSL_VERSION_120);
+ ensureVersionIsAtLeast(GLSL_VERSION_120);
break;
}
}
@@ -97,7 +106,13 @@ bool TVersionGLSL::visitAggregate(Visit, TIntermAggregate *node)
break;
}
case EOpConstructMat2:
+ case EOpConstructMat2x3:
+ case EOpConstructMat2x4:
+ case EOpConstructMat3x2:
case EOpConstructMat3:
+ case EOpConstructMat3x4:
+ case EOpConstructMat4x2:
+ case EOpConstructMat4x3:
case EOpConstructMat4:
{
const TIntermSequence &sequence = *(node->getSequence());
@@ -106,7 +121,7 @@ bool TVersionGLSL::visitAggregate(Visit, TIntermAggregate *node)
TIntermTyped *typed = sequence.front()->getAsTyped();
if (typed && typed->isMatrix())
{
- updateVersion(GLSL_VERSION_120);
+ ensureVersionIsAtLeast(GLSL_VERSION_120);
}
}
break;
@@ -118,7 +133,7 @@ bool TVersionGLSL::visitAggregate(Visit, TIntermAggregate *node)
return visitChildren;
}
-void TVersionGLSL::updateVersion(int version)
+void TVersionGLSL::ensureVersionIsAtLeast(int version)
{
mVersion = std::max(version, mVersion);
}
diff --git a/src/3rdparty/angle/src/compiler/translator/VersionGLSL.h b/src/3rdparty/angle/src/compiler/translator/VersionGLSL.h
index 2b63d5f25d..c41069d42d 100644
--- a/src/3rdparty/angle/src/compiler/translator/VersionGLSL.h
+++ b/src/3rdparty/angle/src/compiler/translator/VersionGLSL.h
@@ -11,6 +11,21 @@
#include "compiler/translator/Pragma.h"
+static const int GLSL_VERSION_110 = 110;
+static const int GLSL_VERSION_120 = 120;
+static const int GLSL_VERSION_130 = 130;
+static const int GLSL_VERSION_140 = 140;
+static const int GLSL_VERSION_150 = 150;
+static const int GLSL_VERSION_330 = 330;
+static const int GLSL_VERSION_400 = 400;
+static const int GLSL_VERSION_410 = 410;
+static const int GLSL_VERSION_420 = 420;
+static const int GLSL_VERSION_430 = 430;
+static const int GLSL_VERSION_440 = 440;
+static const int GLSL_VERSION_450 = 450;
+
+int ShaderOutputTypeToGLSLVersion(ShShaderOutput output);
+
// Traverses the intermediate tree to return the minimum GLSL version
// required to legally access all built-in features used in the shader.
// GLSL 1.1 which is mandated by OpenGL 2.0 provides:
@@ -39,15 +54,14 @@ class TVersionGLSL : public TIntermTraverser
// - matrix/matrix constructors
// - array "out" parameters
// Else 110 is returned.
- int getVersion() { return mVersion; }
+ int getVersion() const { return mVersion; }
- virtual void visitSymbol(TIntermSymbol *);
- virtual bool visitAggregate(Visit, TIntermAggregate *);
-
- protected:
- void updateVersion(int version);
+ void visitSymbol(TIntermSymbol *) override;
+ bool visitAggregate(Visit, TIntermAggregate *) override;
private:
+ void ensureVersionIsAtLeast(int version);
+
int mVersion;
};
diff --git a/src/3rdparty/angle/src/compiler/translator/blocklayout.cpp b/src/3rdparty/angle/src/compiler/translator/blocklayout.cpp
index 7c74105680..ba6322848e 100644
--- a/src/3rdparty/angle/src/compiler/translator/blocklayout.cpp
+++ b/src/3rdparty/angle/src/compiler/translator/blocklayout.cpp
@@ -27,7 +27,10 @@ BlockMemberInfo BlockLayoutEncoder::encodeType(GLenum type, unsigned int arraySi
getBlockLayoutInfo(type, arraySize, isRowMajorMatrix, &arrayStride, &matrixStride);
- const BlockMemberInfo memberInfo(mCurrentOffset * BytesPerComponent, arrayStride * BytesPerComponent, matrixStride * BytesPerComponent, isRowMajorMatrix);
+ const BlockMemberInfo memberInfo(static_cast<int>(mCurrentOffset * BytesPerComponent),
+ static_cast<int>(arrayStride * BytesPerComponent),
+ static_cast<int>(matrixStride * BytesPerComponent),
+ isRowMajorMatrix);
advanceOffset(type, arraySize, isRowMajorMatrix, arrayStride, matrixStride);
diff --git a/src/3rdparty/angle/src/compiler/translator/blocklayout.h b/src/3rdparty/angle/src/compiler/translator/blocklayout.h
index c11357fe66..dd5fe07376 100644
--- a/src/3rdparty/angle/src/compiler/translator/blocklayout.h
+++ b/src/3rdparty/angle/src/compiler/translator/blocklayout.h
@@ -26,6 +26,8 @@ struct InterfaceBlock;
struct COMPILER_EXPORT BlockMemberInfo
{
+ BlockMemberInfo() : offset(-1), arrayStride(-1), matrixStride(-1), isRowMajorMatrix(false) {}
+
BlockMemberInfo(int offset, int arrayStride, int matrixStride, bool isRowMajorMatrix)
: offset(offset),
arrayStride(arrayStride),
@@ -48,12 +50,11 @@ class COMPILER_EXPORT BlockLayoutEncoder
{
public:
BlockLayoutEncoder();
+ virtual ~BlockLayoutEncoder() {}
BlockMemberInfo encodeType(GLenum type, unsigned int arraySize, bool isRowMajorMatrix);
size_t getBlockSize() const { return mCurrentOffset * BytesPerComponent; }
- size_t getCurrentRegister() const { return mCurrentOffset / ComponentsPerRegister; }
- size_t getCurrentElement() const { return mCurrentOffset % ComponentsPerRegister; }
virtual void enterAggregateType() = 0;
virtual void exitAggregateType() = 0;
@@ -81,12 +82,20 @@ class COMPILER_EXPORT Std140BlockEncoder : public BlockLayoutEncoder
public:
Std140BlockEncoder();
- virtual void enterAggregateType();
- virtual void exitAggregateType();
+ void enterAggregateType() override;
+ void exitAggregateType() override;
protected:
- virtual void getBlockLayoutInfo(GLenum type, unsigned int arraySize, bool isRowMajorMatrix, int *arrayStrideOut, int *matrixStrideOut);
- virtual void advanceOffset(GLenum type, unsigned int arraySize, bool isRowMajorMatrix, int arrayStride, int matrixStride);
+ void getBlockLayoutInfo(GLenum type,
+ unsigned int arraySize,
+ bool isRowMajorMatrix,
+ int *arrayStrideOut,
+ int *matrixStrideOut) override;
+ void advanceOffset(GLenum type,
+ unsigned int arraySize,
+ bool isRowMajorMatrix,
+ int arrayStride,
+ int matrixStride) override;
};
}
diff --git a/src/3rdparty/angle/src/compiler/translator/blocklayoutHLSL.cpp b/src/3rdparty/angle/src/compiler/translator/blocklayoutHLSL.cpp
index f32cf2cf89..43119248eb 100644
--- a/src/3rdparty/angle/src/compiler/translator/blocklayoutHLSL.cpp
+++ b/src/3rdparty/angle/src/compiler/translator/blocklayoutHLSL.cpp
@@ -113,9 +113,14 @@ HLSLBlockEncoder::HLSLBlockEncoderStrategy HLSLBlockEncoder::GetStrategyFor(ShSh
{
switch (outputType)
{
- case SH_HLSL9_OUTPUT: return ENCODE_LOOSE;
- case SH_HLSL11_OUTPUT: return ENCODE_PACKED;
- default: UNREACHABLE(); return ENCODE_PACKED;
+ case SH_HLSL_3_0_OUTPUT:
+ return ENCODE_LOOSE;
+ case SH_HLSL_4_1_OUTPUT:
+ case SH_HLSL_4_0_FL9_3_OUTPUT:
+ return ENCODE_PACKED;
+ default:
+ UNREACHABLE();
+ return ENCODE_PACKED;
}
}
@@ -156,6 +161,7 @@ unsigned int HLSLVariableRegisterCount(const Varying &variable, bool transposeMa
unsigned int HLSLVariableRegisterCount(const Uniform &variable, ShShaderOutput outputType)
{
HLSLBlockEncoder encoder(HLSLBlockEncoder::GetStrategyFor(outputType));
+ encoder.setTransposeMatrices(true);
HLSLVariableRegisterCount(variable, &encoder);
const size_t registerBytes = (encoder.BytesPerComponent * encoder.ComponentsPerRegister);
diff --git a/src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraph.cpp b/src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraph.cpp
index 19ddf5c439..4dee0dbd2e 100644
--- a/src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraph.cpp
+++ b/src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraph.cpp
@@ -4,8 +4,6 @@
// found in the LICENSE file.
//
-#pragma warning(disable: 4718)
-
#include "compiler/translator/depgraph/DependencyGraph.h"
#include "compiler/translator/depgraph/DependencyGraphBuilder.h"
diff --git a/src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraph.h b/src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraph.h
index 22db633678..2f7f7b9ab8 100644
--- a/src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraph.h
+++ b/src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraph.h
@@ -46,9 +46,10 @@ protected:
class TGraphParentNode : public TGraphNode {
public:
TGraphParentNode(TIntermNode* node) : TGraphNode(node) {}
- virtual ~TGraphParentNode() {}
+ ~TGraphParentNode() override {}
void addDependentNode(TGraphNode* node) { if (node != this) mDependentNodes.insert(node); }
- virtual void traverse(TDependencyGraphTraverser* graphTraverser);
+ void traverse(TDependencyGraphTraverser *graphTraverser) override;
+
private:
TGraphNodeSet mDependentNodes;
};
@@ -61,10 +62,11 @@ public:
TGraphArgument(TIntermAggregate* intermFunctionCall, int argumentNumber)
: TGraphParentNode(intermFunctionCall)
, mArgumentNumber(argumentNumber) {}
- virtual ~TGraphArgument() {}
+ ~TGraphArgument() override {}
const TIntermAggregate* getIntermFunctionCall() const { return intermNode->getAsAggregate(); }
int getArgumentNumber() const { return mArgumentNumber; }
- virtual void traverse(TDependencyGraphTraverser* graphTraverser);
+ void traverse(TDependencyGraphTraverser *graphTraverser) override;
+
private:
int mArgumentNumber;
};
@@ -76,9 +78,9 @@ class TGraphFunctionCall : public TGraphParentNode {
public:
TGraphFunctionCall(TIntermAggregate* intermFunctionCall)
: TGraphParentNode(intermFunctionCall) {}
- virtual ~TGraphFunctionCall() {}
+ ~TGraphFunctionCall() override {}
const TIntermAggregate* getIntermFunctionCall() const { return intermNode->getAsAggregate(); }
- virtual void traverse(TDependencyGraphTraverser* graphTraverser);
+ void traverse(TDependencyGraphTraverser *graphTraverser) override;
};
//
@@ -87,9 +89,9 @@ public:
class TGraphSymbol : public TGraphParentNode {
public:
TGraphSymbol(TIntermSymbol* intermSymbol) : TGraphParentNode(intermSymbol) {}
- virtual ~TGraphSymbol() {}
+ ~TGraphSymbol() override {}
const TIntermSymbol* getIntermSymbol() const { return intermNode->getAsSymbolNode(); }
- virtual void traverse(TDependencyGraphTraverser* graphTraverser);
+ void traverse(TDependencyGraphTraverser *graphTraverser) override;
};
//
@@ -98,9 +100,9 @@ public:
class TGraphSelection : public TGraphNode {
public:
TGraphSelection(TIntermSelection* intermSelection) : TGraphNode(intermSelection) {}
- virtual ~TGraphSelection() {}
+ ~TGraphSelection() override {}
const TIntermSelection* getIntermSelection() const { return intermNode->getAsSelectionNode(); }
- virtual void traverse(TDependencyGraphTraverser* graphTraverser);
+ void traverse(TDependencyGraphTraverser *graphTraverser) override;
};
//
@@ -109,9 +111,9 @@ public:
class TGraphLoop : public TGraphNode {
public:
TGraphLoop(TIntermLoop* intermLoop) : TGraphNode(intermLoop) {}
- virtual ~TGraphLoop() {}
+ ~TGraphLoop() override {}
const TIntermLoop* getIntermLoop() const { return intermNode->getAsLoopNode(); }
- virtual void traverse(TDependencyGraphTraverser* graphTraverser);
+ void traverse(TDependencyGraphTraverser *graphTraverser) override;
};
//
@@ -120,10 +122,10 @@ public:
class TGraphLogicalOp : public TGraphNode {
public:
TGraphLogicalOp(TIntermBinary* intermLogicalOp) : TGraphNode(intermLogicalOp) {}
- virtual ~TGraphLogicalOp() {}
+ ~TGraphLogicalOp() override {}
const TIntermBinary* getIntermLogicalOp() const { return intermNode->getAsBinaryNode(); }
const char* getOpString() const;
- virtual void traverse(TDependencyGraphTraverser* graphTraverser);
+ void traverse(TDependencyGraphTraverser *graphTraverser) override;
};
//
@@ -140,27 +142,11 @@ class TDependencyGraph {
public:
TDependencyGraph(TIntermNode* intermNode);
~TDependencyGraph();
- TGraphNodeVector::const_iterator begin() const { return mAllNodes.begin(); }
- TGraphNodeVector::const_iterator end() const { return mAllNodes.end(); }
-
- TGraphSymbolVector::const_iterator beginSamplerSymbols() const
- {
- return mSamplerSymbols.begin();
- }
-
- TGraphSymbolVector::const_iterator endSamplerSymbols() const
- {
- return mSamplerSymbols.end();
- }
-
- TFunctionCallVector::const_iterator beginUserDefinedFunctionCalls() const
- {
- return mUserDefinedFunctionCalls.begin();
- }
-
- TFunctionCallVector::const_iterator endUserDefinedFunctionCalls() const
+ const TGraphNodeVector &allNodes() const { return mAllNodes; }
+ const TGraphSymbolVector &samplerSymbols() const { return mSamplerSymbols; }
+ const TFunctionCallVector &userDefinedFunctionCalls() const
{
- return mUserDefinedFunctionCalls.end();
+ return mUserDefinedFunctionCalls;
}
TGraphArgument* createArgument(TIntermAggregate* intermFunctionCall, int argumentNumber);
@@ -189,6 +175,7 @@ private:
class TDependencyGraphTraverser : angle::NonCopyable {
public:
TDependencyGraphTraverser() : mDepth(0) {}
+ virtual ~TDependencyGraphTraverser() {}
virtual void visitSymbol(TGraphSymbol* symbol) {};
virtual void visitArgument(TGraphArgument* selection) {};
diff --git a/src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraphBuilder.h b/src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraphBuilder.h
index f7b3bd4b43..c7b54f66b7 100644
--- a/src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraphBuilder.h
+++ b/src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraphBuilder.h
@@ -18,11 +18,11 @@ class TDependencyGraphBuilder : public TIntermTraverser
public:
static void build(TIntermNode *node, TDependencyGraph *graph);
- virtual void visitSymbol(TIntermSymbol *);
- virtual bool visitBinary(Visit visit, TIntermBinary *);
- virtual bool visitSelection(Visit visit, TIntermSelection *);
- virtual bool visitAggregate(Visit visit, TIntermAggregate *);
- virtual bool visitLoop(Visit visit, TIntermLoop *);
+ void visitSymbol(TIntermSymbol *) override;
+ bool visitBinary(Visit visit, TIntermBinary *) override;
+ bool visitSelection(Visit visit, TIntermSelection *) override;
+ bool visitAggregate(Visit visit, TIntermAggregate *) override;
+ bool visitLoop(Visit visit, TIntermLoop *) override;
private:
typedef std::stack<TGraphSymbol *> TSymbolStack;
diff --git a/src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraphOutput.cpp b/src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraphOutput.cpp
index e226333545..32a2f30141 100644
--- a/src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraphOutput.cpp
+++ b/src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraphOutput.cpp
@@ -54,9 +54,8 @@ void TDependencyGraphOutput::outputAllSpanningTrees(TDependencyGraph& graph)
{
mSink << "\n";
- for (TGraphNodeVector::const_iterator iter = graph.begin(); iter != graph.end(); ++iter)
+ for (auto symbol : graph.allNodes())
{
- TGraphNode* symbol = *iter;
mSink << "--- Dependency graph spanning tree ---\n";
clearVisited();
symbol->traverse(this);
diff --git a/src/3rdparty/angle/src/compiler/translator/glslang.h b/src/3rdparty/angle/src/compiler/translator/glslang.h
index db31e6946c..0555e96d45 100644
--- a/src/3rdparty/angle/src/compiler/translator/glslang.h
+++ b/src/3rdparty/angle/src/compiler/translator/glslang.h
@@ -7,7 +7,7 @@
#ifndef COMPILER_TRANSLATOR_GLSLANG_H_
#define COMPILER_TRANSLATOR_GLSLANG_H_
-struct TParseContext;
+class TParseContext;
extern int glslang_initialize(TParseContext* context);
extern int glslang_finalize(TParseContext* context);
diff --git a/src/3rdparty/angle/src/compiler/translator/glslang.l b/src/3rdparty/angle/src/compiler/translator/glslang.l
index ee4d28b6d6..d09358dd8a 100644
--- a/src/3rdparty/angle/src/compiler/translator/glslang.l
+++ b/src/3rdparty/angle/src/compiler/translator/glslang.l
@@ -28,8 +28,10 @@ WHICH GENERATES THE GLSL ES LEXER (glslang_lex.cpp).
#pragma GCC diagnostic ignored "-Wunused-variable"
#pragma GCC diagnostic ignored "-Wswitch-enum"
#elif defined(_MSC_VER)
+#pragma warning(disable: 4005)
#pragma warning(disable: 4065)
#pragma warning(disable: 4189)
+#pragma warning(disable: 4244)
#pragma warning(disable: 4505)
#pragma warning(disable: 4701)
#pragma warning(disable: 4702)
@@ -49,6 +51,13 @@ WHICH GENERATES THE GLSL ES LEXER (glslang_lex.cpp).
#pragma warning(disable : 4102)
#endif
+// Workaround for flex using the register keyword, deprecated in C++11.
+#ifdef __cplusplus
+#if __cplusplus > 199711L
+#define register
+#endif
+#endif
+
#define YY_USER_ACTION \
yylloc->first_file = yylloc->last_file = yycolumn; \
yylloc->first_line = yylloc->last_line = yylineno;
@@ -63,7 +72,7 @@ static int ES2_reserved_ES3_keyword(TParseContext *context, int token);
static int ES2_keyword_ES3_reserved(TParseContext *context, int token);
static int ES2_ident_ES3_keyword(TParseContext *context, int token);
static int uint_constant(TParseContext *context);
-static int int_constant(yyscan_t yyscanner);
+static int int_constant(TParseContext *context);
static int float_constant(yyscan_t yyscanner);
static int floatsuffix_check(TParseContext* context);
%}
@@ -237,7 +246,7 @@ O [0-7]
"sampler2DMSArray" |
"isampler2DMSArray" |
"usampler2DMSArray" {
- if (context->shaderVersion < 300) {
+ if (context->getShaderVersion() < 300) {
yylval->lex.string = NewPoolTString(yytext);
return check_type(yyscanner);
}
@@ -246,7 +255,7 @@ O [0-7]
/* Reserved keywords in GLSL ES 1.00 that are not reserved in GLSL ES 3.00 */
"packed" {
- if (context->shaderVersion >= 300)
+ if (context->getShaderVersion() >= 300)
{
yylval->lex.string = NewPoolTString(yytext);
return check_type(yyscanner);
@@ -312,9 +321,9 @@ O [0-7]
return check_type(yyscanner);
}
-0[xX]{H}+ { return int_constant(yyscanner); }
-0{O}+ { return int_constant(yyscanner); }
-{D}+ { return int_constant(yyscanner); }
+0[xX]{H}+ { return int_constant(context); }
+0{O}+ { return int_constant(context); }
+{D}+ { return int_constant(context); }
0[xX]{H}+[uU] { return uint_constant(context); }
0{O}+[uU] { return uint_constant(context); }
@@ -390,7 +399,7 @@ O [0-7]
yy_size_t string_input(char* buf, yy_size_t max_size, yyscan_t yyscanner) {
pp::Token token;
- yyget_extra(yyscanner)->preprocessor.lex(&token);
+ yyget_extra(yyscanner)->getPreprocessor().lex(&token);
yy_size_t len = token.type == pp::Token::LAST ? 0 : token.text.size();
if (len < max_size)
memcpy(buf, token.text.c_str(), len);
@@ -408,7 +417,7 @@ int check_type(yyscan_t yyscanner) {
struct yyguts_t* yyg = (struct yyguts_t*) yyscanner;
int token = IDENTIFIER;
- TSymbol* symbol = yyextra->symbolTable.find(yytext, yyextra->shaderVersion);
+ TSymbol* symbol = yyextra->symbolTable.find(yytext, yyextra->getShaderVersion());
if (symbol && symbol->isVariable()) {
TVariable* variable = static_cast<TVariable*>(symbol);
if (variable->isUserType()) {
@@ -429,9 +438,9 @@ int reserved_word(yyscan_t yyscanner) {
int ES2_reserved_ES3_keyword(TParseContext *context, int token)
{
- yyscan_t yyscanner = (yyscan_t) context->scanner;
+ yyscan_t yyscanner = (yyscan_t) context->getScanner();
- if (context->shaderVersion < 300)
+ if (context->getShaderVersion() < 300)
{
return reserved_word(yyscanner);
}
@@ -441,9 +450,9 @@ int ES2_reserved_ES3_keyword(TParseContext *context, int token)
int ES2_keyword_ES3_reserved(TParseContext *context, int token)
{
- yyscan_t yyscanner = (yyscan_t) context->scanner;
+ yyscan_t yyscanner = (yyscan_t) context->getScanner();
- if (context->shaderVersion >= 300)
+ if (context->getShaderVersion() >= 300)
{
return reserved_word(yyscanner);
}
@@ -453,11 +462,11 @@ int ES2_keyword_ES3_reserved(TParseContext *context, int token)
int ES2_ident_ES3_keyword(TParseContext *context, int token)
{
- struct yyguts_t* yyg = (struct yyguts_t*) context->scanner;
- yyscan_t yyscanner = (yyscan_t) context->scanner;
+ struct yyguts_t* yyg = (struct yyguts_t*) context->getScanner();
+ yyscan_t yyscanner = (yyscan_t) context->getScanner();
// not a reserved word in GLSL ES 1.00, so could be used as an identifier/type name
- if (context->shaderVersion < 300)
+ if (context->getShaderVersion() < 300)
{
yylval->lex.string = NewPoolTString(yytext);
return check_type(yyscanner);
@@ -468,34 +477,35 @@ int ES2_ident_ES3_keyword(TParseContext *context, int token)
int uint_constant(TParseContext *context)
{
- struct yyguts_t* yyg = (struct yyguts_t*) context->scanner;
- yyscan_t yyscanner = (yyscan_t) context->scanner;
+ struct yyguts_t* yyg = (struct yyguts_t*) context->getScanner();
- if (context->shaderVersion < 300)
+ if (context->getShaderVersion() < 300)
{
context->error(*yylloc, "Unsigned integers are unsupported prior to GLSL ES 3.00", yytext, "");
context->recover();
return 0;
}
- if (!atoi_clamp(yytext, &(yylval->lex.i)))
- yyextra->warning(*yylloc, "Integer overflow", yytext, "");
+ if (!atoi_clamp(yytext, &(yylval->lex.u)))
+ yyextra->error(*yylloc, "Integer overflow", yytext, "");
return UINTCONSTANT;
}
int floatsuffix_check(TParseContext* context)
{
- struct yyguts_t* yyg = (struct yyguts_t*) context->scanner;
+ struct yyguts_t* yyg = (struct yyguts_t*) context->getScanner();
- if (context->shaderVersion < 300)
+ if (context->getShaderVersion() < 300)
{
context->error(*yylloc, "Floating-point suffix unsupported prior to GLSL ES 3.00", yytext);
context->recover();
return 0;
}
- if (!atof_clamp(yytext, &(yylval->lex.f)))
+ std::string text = yytext;
+ text.resize(text.size() - 1);
+ if (!strtof_clamp(text, &(yylval->lex.f)))
yyextra->warning(*yylloc, "Float overflow", yytext, "");
return(FLOATCONSTANT);
@@ -506,18 +516,25 @@ void yyerror(YYLTYPE* lloc, TParseContext* context, void *scanner, const char* r
context->recover();
}
-int int_constant(yyscan_t yyscanner) {
- struct yyguts_t* yyg = (struct yyguts_t*) yyscanner;
+int int_constant(TParseContext *context) {
+ struct yyguts_t* yyg = (struct yyguts_t*) context->getScanner();
- if (!atoi_clamp(yytext, &(yylval->lex.i)))
- yyextra->warning(*yylloc, "Integer overflow", yytext, "");
+ unsigned int u;
+ if (!atoi_clamp(yytext, &u))
+ {
+ if (context->getShaderVersion() >= 300)
+ yyextra->error(*yylloc, "Integer overflow", yytext, "");
+ else
+ yyextra->warning(*yylloc, "Integer overflow", yytext, "");
+ }
+ yylval->lex.i = static_cast<int>(u);
return INTCONSTANT;
}
int float_constant(yyscan_t yyscanner) {
struct yyguts_t* yyg = (struct yyguts_t*) yyscanner;
- if (!atof_clamp(yytext, &(yylval->lex.f)))
+ if (!strtof_clamp(yytext, &(yylval->lex.f)))
yyextra->warning(*yylloc, "Float overflow", yytext, "");
return FLOATCONSTANT;
}
@@ -527,15 +544,15 @@ int glslang_initialize(TParseContext* context) {
if (yylex_init_extra(context, &scanner))
return 1;
- context->scanner = scanner;
+ context->setScanner(scanner);
return 0;
}
int glslang_finalize(TParseContext* context) {
- yyscan_t scanner = context->scanner;
+ yyscan_t scanner = context->getScanner();
if (scanner == NULL) return 0;
- context->scanner = NULL;
+ context->setScanner(NULL);
yylex_destroy(scanner);
return 0;
@@ -543,24 +560,26 @@ int glslang_finalize(TParseContext* context) {
int glslang_scan(size_t count, const char* const string[], const int length[],
TParseContext* context) {
- yyrestart(NULL, context->scanner);
- yyset_column(0, context->scanner);
- yyset_lineno(1, context->scanner);
+ yyrestart(NULL, context->getScanner());
+ yyset_column(0, context->getScanner());
+ yyset_lineno(1, context->getScanner());
// Initialize preprocessor.
- if (!context->preprocessor.init(count, string, length))
+ pp::Preprocessor *preprocessor = &context->getPreprocessor();
+
+ if (!preprocessor->init(count, string, length))
return 1;
// Define extension macros.
const TExtensionBehavior& extBehavior = context->extensionBehavior();
for (TExtensionBehavior::const_iterator iter = extBehavior.begin();
iter != extBehavior.end(); ++iter) {
- context->preprocessor.predefineMacro(iter->first.c_str(), 1);
+ preprocessor->predefineMacro(iter->first.c_str(), 1);
}
- if (context->fragmentPrecisionHigh)
- context->preprocessor.predefineMacro("GL_FRAGMENT_PRECISION_HIGH", 1);
+ if (context->getFragmentPrecisionHigh())
+ preprocessor->predefineMacro("GL_FRAGMENT_PRECISION_HIGH", 1);
- context->preprocessor.setMaxTokenSize(GetGlobalMaxTokenSize(context->shaderSpec));
+ preprocessor->setMaxTokenSize(GetGlobalMaxTokenSize(context->getShaderSpec()));
return 0;
}
diff --git a/src/3rdparty/angle/src/compiler/translator/glslang.y b/src/3rdparty/angle/src/compiler/translator/glslang.y
index 6024898cb0..aba2706311 100644
--- a/src/3rdparty/angle/src/compiler/translator/glslang.y
+++ b/src/3rdparty/angle/src/compiler/translator/glslang.y
@@ -30,12 +30,14 @@ WHICH GENERATES THE GLSL ES PARSER (glslang_tab.cpp AND glslang_tab.h).
#elif defined(_MSC_VER)
#pragma warning(disable: 4065)
#pragma warning(disable: 4189)
+#pragma warning(disable: 4244)
#pragma warning(disable: 4505)
#pragma warning(disable: 4701)
#pragma warning(disable: 4702)
#endif
#include "angle_gl.h"
+#include "compiler/translator/Cache.h"
#include "compiler/translator/SymbolTable.h"
#include "compiler/translator/ParseContext.h"
#include "GLSLANG/ShaderLang.h"
@@ -109,28 +111,28 @@ extern void yyerror(YYLTYPE* yylloc, TParseContext* context, void *scanner, cons
} while (0)
#define VERTEX_ONLY(S, L) { \
- if (context->shaderType != GL_VERTEX_SHADER) { \
+ if (context->getShaderType() != GL_VERTEX_SHADER) { \
context->error(L, " supported in vertex shaders only ", S); \
context->recover(); \
} \
}
#define FRAG_ONLY(S, L) { \
- if (context->shaderType != GL_FRAGMENT_SHADER) { \
+ if (context->getShaderType() != GL_FRAGMENT_SHADER) { \
context->error(L, " supported in fragment shaders only ", S); \
context->recover(); \
} \
}
#define ES2_ONLY(S, L) { \
- if (context->shaderVersion != 100) { \
+ if (context->getShaderVersion() != 100) { \
context->error(L, " supported in GLSL ES 1.00 only ", S); \
context->recover(); \
} \
}
#define ES3_ONLY(TOKEN, LINE, REASON) { \
- if (context->shaderVersion != 300) { \
+ if (context->getShaderVersion() != 300) { \
context->error(LINE, REASON " supported in GLSL ES 3.00 only ", TOKEN); \
context->recover(); \
} \
@@ -176,10 +178,10 @@ extern void yyerror(YYLTYPE* yylloc, TParseContext* context, void *scanner, cons
%type <interm.intermNode> translation_unit function_definition
%type <interm.intermNode> statement simple_statement
-%type <interm.intermAggregate> statement_list compound_statement
+%type <interm.intermAggregate> statement_list compound_statement compound_statement_no_new_scope
%type <interm.intermNode> declaration_statement selection_statement expression_statement
%type <interm.intermNode> declaration external_declaration
-%type <interm.intermNode> for_init_statement compound_statement_no_new_scope
+%type <interm.intermNode> for_init_statement
%type <interm.nodePair> selection_rest_statement for_rest_statement
%type <interm.intermSwitch> switch_statement
%type <interm.intermCase> case_label
@@ -213,21 +215,7 @@ identifier
variable_identifier
: IDENTIFIER {
// The symbol table search was done in the lexical phase
- const TVariable *variable = context->getNamedVariable(@1, $1.string, $1.symbol);
-
- if (variable->getType().getQualifier() == EvqConst)
- {
- ConstantUnion* constArray = variable->getConstPointer();
- TType t(variable->getType());
- $$ = context->intermediate.addConstantUnion(constArray, t, @1);
- }
- else
- {
- $$ = context->intermediate.addSymbol(variable->getUniqueId(),
- variable->getName(),
- variable->getType(),
- @1);
- }
+ $$ = context->parseVariableIdentifier(@1, $1.string, $1.symbol);
// don't delete $1.string, it's used by error recovery, and the pool
// pop will reclaim the memory
@@ -239,22 +227,22 @@ primary_expression
$$ = $1;
}
| INTCONSTANT {
- ConstantUnion *unionArray = new ConstantUnion[1];
+ TConstantUnion *unionArray = new TConstantUnion[1];
unionArray->setIConst($1.i);
$$ = context->intermediate.addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), @1);
}
| UINTCONSTANT {
- ConstantUnion *unionArray = new ConstantUnion[1];
+ TConstantUnion *unionArray = new TConstantUnion[1];
unionArray->setUConst($1.u);
$$ = context->intermediate.addConstantUnion(unionArray, TType(EbtUInt, EbpUndefined, EvqConst), @1);
}
| FLOATCONSTANT {
- ConstantUnion *unionArray = new ConstantUnion[1];
+ TConstantUnion *unionArray = new TConstantUnion[1];
unionArray->setFConst($1.f);
$$ = context->intermediate.addConstantUnion(unionArray, TType(EbtFloat, EbpUndefined, EvqConst), @1);
}
| BOOLCONSTANT {
- ConstantUnion *unionArray = new ConstantUnion[1];
+ TConstantUnion *unionArray = new TConstantUnion[1];
unionArray->setBConst($1.b);
$$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), @1);
}
@@ -295,7 +283,7 @@ integer_expression
function_call
: function_call_or_method {
bool fatalError = false;
- $$ = context->addFunctionCallOrMethod($1.function, $1.intermNode, @1, &fatalError);
+ $$ = context->addFunctionCallOrMethod($1.function, $1.nodePair.node1, $1.nodePair.node2, @1, &fatalError);
if (fatalError)
{
YYERROR;
@@ -306,11 +294,12 @@ function_call
function_call_or_method
: function_call_generic {
$$ = $1;
+ $$.nodePair.node2 = nullptr;
}
| postfix_expression DOT function_call_generic {
- context->error(@3, "methods are not supported", "");
- context->recover();
+ ES3_ONLY("", @3, "methods");
$$ = $3;
+ $$.nodePair.node2 = $1;
}
;
@@ -326,26 +315,26 @@ function_call_generic
function_call_header_no_parameters
: function_call_header VOID_TYPE {
$$.function = $1;
- $$.intermNode = 0;
+ $$.nodePair.node1 = nullptr;
}
| function_call_header {
$$.function = $1;
- $$.intermNode = 0;
+ $$.nodePair.node1 = nullptr;
}
;
function_call_header_with_parameters
: function_call_header assignment_expression {
- TParameter param = { 0, new TType($2->getType()) };
- $1->addParameter(param);
+ const TType *type = new TType($2->getType());
+ $1->addParameter(TConstParameter(type));
$$.function = $1;
- $$.intermNode = $2;
+ $$.nodePair.node1 = context->intermediate.makeAggregate($2, @2);
}
| function_call_header_with_parameters COMMA assignment_expression {
- TParameter param = { 0, new TType($3->getType()) };
- $1.function->addParameter(param);
+ const TType *type = new TType($3->getType());
+ $1.function->addParameter(TConstParameter(type));
$$.function = $1.function;
- $$.intermNode = context->intermediate.growAggregate($1.intermNode, $3, @2);
+ $$.nodePair.node1 = context->intermediate.growAggregate($1.intermNode, $3, @2);
}
;
@@ -358,20 +347,23 @@ function_call_header
// Grammar Note: Constructors look like functions, but are recognized as types.
function_identifier
- : type_specifier_nonarray {
+ : type_specifier_no_prec {
+ if ($1.array) {
+ ES3_ONLY("[]", @1, "array constructor");
+ }
$$ = context->addConstructorFunc($1);
}
| IDENTIFIER {
if (context->reservedErrorCheck(@1, *$1.string))
context->recover();
- TType type(EbtVoid, EbpUndefined);
+ const TType *type = TCache::getType(EbtVoid, EbpUndefined);
TFunction *function = new TFunction($1.string, type);
$$ = function;
}
| FIELD_SELECTION {
if (context->reservedErrorCheck(@1, *$1.string))
context->recover();
- TType type(EbtVoid, EbpUndefined);
+ const TType *type = TCache::getType(EbtVoid, EbpUndefined);
TFunction *function = new TFunction($1.string, type);
$$ = function;
}
@@ -517,18 +509,7 @@ logical_or_expression
conditional_expression
: logical_or_expression { $$ = $1; }
| logical_or_expression QUESTION expression COLON assignment_expression {
- if (context->boolErrorCheck(@2, $1))
- context->recover();
-
- $$ = context->intermediate.addSelection($1, $3, $5, @2);
- if ($3->getType() != $5->getType())
- $$ = 0;
-
- if ($$ == 0) {
- context->binaryOpError(@2, ":", $3->getCompleteString(), $5->getCompleteString());
- context->recover();
- $$ = $5;
- }
+ $$ = context->addTernarySelection($1, $3, $5, @2);
}
;
@@ -578,12 +559,7 @@ expression
$$ = $1;
}
| expression COMMA assignment_expression {
- $$ = context->intermediate.addComma($1, $3, @2);
- if ($$ == 0) {
- context->binaryOpError(@2, ",", $1->getCompleteString(), $3->getCompleteString());
- context->recover();
- $$ = $3;
- }
+ $$ = context->addComma($1, $3, @2);
}
;
@@ -604,32 +580,8 @@ enter_struct
;
declaration
- : function_prototype SEMICOLON {
- TFunction &function = *($1.function);
-
- TIntermAggregate *prototype = new TIntermAggregate;
- prototype->setType(function.getReturnType());
- prototype->setName(function.getMangledName());
-
- for (size_t i = 0; i < function.getParamCount(); i++)
- {
- const TParameter &param = function.getParam(i);
- if (param.name != 0)
- {
- TVariable variable(param.name, *param.type);
-
- prototype = context->intermediate.growAggregate(prototype, context->intermediate.addSymbol(variable.getUniqueId(), variable.getName(), variable.getType(), @1), @1);
- }
- else
- {
- prototype = context->intermediate.growAggregate(prototype, context->intermediate.addSymbol(0, "", *param.type, @1), @1);
- }
- }
-
- prototype->setOp(EOpPrototype);
- $$ = prototype;
-
- context->symbolTable.pop();
+ : function_prototype SEMICOLON {
+ $$ = context->addFunctionPrototypeDeclaration(*($1.function), @1);
}
| init_declarator_list SEMICOLON {
TIntermAggregate *aggNode = $1.intermAggregate;
@@ -638,7 +590,7 @@ declaration
$$ = aggNode;
}
| PRECISION precision_qualifier type_specifier_no_prec SEMICOLON {
- if (($2 == EbpHigh) && (context->shaderType == GL_FRAGMENT_SHADER) && !context->fragmentPrecisionHigh) {
+ if (($2 == EbpHigh) && (context->getShaderType() == GL_FRAGMENT_SHADER) && !context->getFragmentPrecisionHigh()) {
context->error(@1, "precision is not supported in fragment shader", "highp");
context->recover();
}
@@ -668,57 +620,7 @@ declaration
function_prototype
: function_declarator RIGHT_PAREN {
- //
- // Multiple declarations of the same function are allowed.
- //
- // If this is a definition, the definition production code will check for redefinitions
- // (we don't know at this point if it's a definition or not).
- //
- // Redeclarations are allowed. But, return types and parameter qualifiers must match.
- //
- TFunction* prevDec = static_cast<TFunction*>(context->symbolTable.find($1->getMangledName(), context->shaderVersion));
- if (prevDec) {
- if (prevDec->getReturnType() != $1->getReturnType()) {
- context->error(@2, "overloaded functions must have the same return type", $1->getReturnType().getBasicString());
- context->recover();
- }
- for (size_t i = 0; i < prevDec->getParamCount(); ++i) {
- if (prevDec->getParam(i).type->getQualifier() != $1->getParam(i).type->getQualifier()) {
- context->error(@2, "overloaded functions must have the same parameter qualifiers", $1->getParam(i).type->getQualifierString());
- context->recover();
- }
- }
- }
-
- //
- // Check for previously declared variables using the same name.
- //
- TSymbol *prevSym = context->symbolTable.find($1->getName(), context->shaderVersion);
- if (prevSym)
- {
- if (!prevSym->isFunction())
- {
- context->error(@2, "redefinition", $1->getName().c_str(), "function");
- context->recover();
- }
- }
- else
- {
- // Insert the unmangled name to detect potential future redefinition as a variable.
- TFunction *function = new TFunction(NewPoolTString($1->getName().c_str()), $1->getReturnType());
- context->symbolTable.getOuterLevel()->insertUnmangled(function);
- }
-
- //
- // If this is a redeclaration, it could also be a definition,
- // in which case, we want to use the variable names from this one, and not the one that's
- // being redeclared. So, pass back up this declaration, not the one in the symbol table.
- //
- $$.function = $1;
-
- // We're at the inner scope level of the function's arguments and body statement.
- // Add the function prototype to the surrounding scope instead.
- context->symbolTable.getOuterLevel()->insert($$.function);
+ $$.function = context->parseFunctionDeclarator(@2, $1);
}
;
@@ -737,7 +639,7 @@ function_header_with_parameters
// Add the parameter
$$ = $1;
if ($2.param.type->getBasicType() != EbtVoid)
- $1->addParameter($2.param);
+ $1->addParameter($2.param.turnToConst());
else
delete $2.param.type;
}
@@ -756,24 +658,30 @@ function_header_with_parameters
} else {
// Add the parameter
$$ = $1;
- $1->addParameter($3.param);
+ $1->addParameter($3.param.turnToConst());
}
}
;
function_header
: fully_specified_type IDENTIFIER LEFT_PAREN {
- if ($1.qualifier != EvqGlobal && $1.qualifier != EvqTemporary) {
+ if ($1.qualifier != EvqGlobal && $1.qualifier != EvqTemporary)
+ {
context->error(@2, "no qualifiers allowed for function return", getQualifierString($1.qualifier));
context->recover();
}
+ if (!$1.layoutQualifier.isEmpty())
+ {
+ context->error(@2, "no qualifiers allowed for function return", "layout");
+ context->recover();
+ }
// make sure a sampler is not involved as well...
- if (context->structQualifierErrorCheck(@2, $1))
+ if (context->samplerErrorCheck(@2, $1, "samplers can't be function return values"))
context->recover();
// Add the function as a prototype after parsing it (we do not support recursion)
TFunction *function;
- TType type($1);
+ const TType *type = new TType($1);
function = new TFunction($2.string, type);
$$ = function;
@@ -804,7 +712,7 @@ parameter_declarator
int size;
if (context->arraySizeErrorCheck(@3, $4, size))
context->recover();
- $1.setArray(true, size);
+ $1.setArraySize(size);
TType* type = new TType($1);
TParameter param = { $2.string, type };
@@ -878,15 +786,21 @@ init_declarator_list
}
| init_declarator_list COMMA identifier {
$$ = $1;
- $$.intermAggregate = context->parseDeclarator($$.type, $1.intermAggregate, $3.symbol, @3, *$3.string);
+ $$.intermAggregate = context->parseDeclarator($$.type, $1.intermAggregate, @3, *$3.string);
}
- | init_declarator_list COMMA identifier LEFT_BRACKET RIGHT_BRACKET {
+ | init_declarator_list COMMA identifier LEFT_BRACKET constant_expression RIGHT_BRACKET {
$$ = $1;
- context->parseArrayDeclarator($$.type, @3, *$3.string, @4, NULL, NULL);
+ $$.intermAggregate = context->parseArrayDeclarator($$.type, $1.intermAggregate, @3, *$3.string, @4, $5);
}
- | init_declarator_list COMMA identifier LEFT_BRACKET constant_expression RIGHT_BRACKET {
+ | init_declarator_list COMMA identifier LEFT_BRACKET RIGHT_BRACKET EQUAL initializer {
+ ES3_ONLY("[]", @3, "implicitly sized array");
+ $$ = $1;
+ $$.intermAggregate = context->parseArrayInitDeclarator($$.type, $1.intermAggregate, @3, *$3.string, @4, nullptr, @6, $7);
+ }
+ | init_declarator_list COMMA identifier LEFT_BRACKET constant_expression RIGHT_BRACKET EQUAL initializer {
+ ES3_ONLY("=", @7, "first-class arrays (array initializer)");
$$ = $1;
- $$.intermAggregate = context->parseArrayDeclarator($$.type, @3, *$3.string, @4, $1.intermNode, $5);
+ $$.intermAggregate = context->parseArrayInitDeclarator($$.type, $1.intermAggregate, @3, *$3.string, @4, $5, @7, $8);
}
| init_declarator_list COMMA identifier EQUAL initializer {
$$ = $1;
@@ -903,17 +817,20 @@ single_declaration
$$.type = $1;
$$.intermAggregate = context->parseSingleDeclaration($$.type, @2, *$2.string);
}
- | fully_specified_type identifier LEFT_BRACKET RIGHT_BRACKET {
- context->error(@2, "unsized array declarations not supported", $2.string->c_str());
- context->recover();
-
- $$.type = $1;
- $$.intermAggregate = context->parseSingleDeclaration($$.type, @2, *$2.string);
- }
| fully_specified_type identifier LEFT_BRACKET constant_expression RIGHT_BRACKET {
$$.type = $1;
$$.intermAggregate = context->parseSingleArrayDeclaration($$.type, @2, *$2.string, @3, $4);
}
+ | fully_specified_type identifier LEFT_BRACKET RIGHT_BRACKET EQUAL initializer {
+ ES3_ONLY("[]", @3, "implicitly sized array");
+ $$.type = $1;
+ $$.intermAggregate = context->parseSingleArrayInitDeclaration($$.type, @2, *$2.string, @3, nullptr, @5, $6);
+ }
+ | fully_specified_type identifier LEFT_BRACKET constant_expression RIGHT_BRACKET EQUAL initializer {
+ ES3_ONLY("=", @6, "first-class arrays (array initializer)");
+ $$.type = $1;
+ $$.intermAggregate = context->parseSingleArrayInitDeclaration($$.type, @2, *$2.string, @3, $4, @6, $7);
+ }
| fully_specified_type identifier EQUAL initializer {
$$.type = $1;
$$.intermAggregate = context->parseSingleInitDeclaration($$.type, @2, *$2.string, @3, $4);
@@ -929,13 +846,14 @@ fully_specified_type
$$ = $1;
if ($1.array) {
- context->error(@1, "not supported", "first-class array");
- context->recover();
- $1.setArray(false);
+ ES3_ONLY("[]", @1, "first-class-array");
+ if (context->getShaderVersion() != 300) {
+ $1.clearArrayness();
+ }
}
}
| type_qualifier type_specifier {
- $$ = context->addFullySpecifiedType($1.qualifier, $1.layoutQualifier, $2);
+ $$ = context->addFullySpecifiedType($1.qualifier, $1.invariant, $1.layoutQualifier, $2);
}
;
@@ -966,7 +884,7 @@ type_qualifier
ES2_ONLY("varying", @1);
if (context->globalErrorCheck(@1, context->symbolTable.atGlobalLevel(), "varying"))
context->recover();
- if (context->shaderType == GL_VERTEX_SHADER)
+ if (context->getShaderType() == GL_VERTEX_SHADER)
$$.setBasic(EbtVoid, EvqVaryingOut, @1);
else
$$.setBasic(EbtVoid, EvqVaryingIn, @1);
@@ -975,18 +893,19 @@ type_qualifier
ES2_ONLY("varying", @1);
if (context->globalErrorCheck(@1, context->symbolTable.atGlobalLevel(), "invariant varying"))
context->recover();
- if (context->shaderType == GL_VERTEX_SHADER)
- $$.setBasic(EbtVoid, EvqInvariantVaryingOut, @1);
+ if (context->getShaderType() == GL_VERTEX_SHADER)
+ $$.setBasic(EbtVoid, EvqVaryingOut, @1);
else
- $$.setBasic(EbtVoid, EvqInvariantVaryingIn, @1);
+ $$.setBasic(EbtVoid, EvqVaryingIn, @1);
+ $$.invariant = true;
}
| storage_qualifier {
- if ($1.qualifier != EvqConst && !context->symbolTable.atGlobalLevel()) {
+ if ($1.qualifier != EvqConst && !context->symbolTable.atGlobalLevel())
+ {
context->error(@1, "Local variables can only use the const storage qualifier.", getQualifierString($1.qualifier));
context->recover();
- } else {
- $$.setBasic(EbtVoid, $1.qualifier, @1);
}
+ $$.setBasic(EbtVoid, $1.qualifier, @1);
}
| interpolation_qualifier storage_qualifier {
$$ = context->joinInterpolationQualifiers(@1, $1.qualifier, @2, $2.qualifier);
@@ -1006,6 +925,16 @@ type_qualifier
$$.setBasic(EbtVoid, $2.qualifier, @2);
$$.layoutQualifier = $1;
}
+ | INVARIANT storage_qualifier {
+ context->es3InvariantErrorCheck($2.qualifier, @1);
+ $$.setBasic(EbtVoid, $2.qualifier, @2);
+ $$.invariant = true;
+ }
+ | INVARIANT interpolation_qualifier storage_qualifier {
+ context->es3InvariantErrorCheck($3.qualifier, @1);
+ $$ = context->joinInterpolationQualifiers(@2, $2.qualifier, @3, $3.qualifier);
+ $$.invariant = true;
+ }
;
storage_qualifier
@@ -1014,29 +943,29 @@ storage_qualifier
}
| IN_QUAL {
ES3_ONLY("in", @1, "storage qualifier");
- $$.qualifier = (context->shaderType == GL_FRAGMENT_SHADER) ? EvqFragmentIn : EvqVertexIn;
+ $$.qualifier = (context->getShaderType() == GL_FRAGMENT_SHADER) ? EvqFragmentIn : EvqVertexIn;
}
| OUT_QUAL {
ES3_ONLY("out", @1, "storage qualifier");
- $$.qualifier = (context->shaderType == GL_FRAGMENT_SHADER) ? EvqFragmentOut : EvqVertexOut;
+ $$.qualifier = (context->getShaderType() == GL_FRAGMENT_SHADER) ? EvqFragmentOut : EvqVertexOut;
}
| CENTROID IN_QUAL {
ES3_ONLY("centroid in", @1, "storage qualifier");
- if (context->shaderType == GL_VERTEX_SHADER)
+ if (context->getShaderType() == GL_VERTEX_SHADER)
{
context->error(@1, "invalid storage qualifier", "it is an error to use 'centroid in' in the vertex shader");
context->recover();
}
- $$.qualifier = (context->shaderType == GL_FRAGMENT_SHADER) ? EvqCentroidIn : EvqVertexIn;
+ $$.qualifier = (context->getShaderType() == GL_FRAGMENT_SHADER) ? EvqCentroidIn : EvqVertexIn;
}
| CENTROID OUT_QUAL {
ES3_ONLY("centroid out", @1, "storage qualifier");
- if (context->shaderType == GL_FRAGMENT_SHADER)
+ if (context->getShaderType() == GL_FRAGMENT_SHADER)
{
context->error(@1, "invalid storage qualifier", "it is an error to use 'centroid out' in the fragment shader");
context->recover();
}
- $$.qualifier = (context->shaderType == GL_FRAGMENT_SHADER) ? EvqFragmentOut : EvqCentroidOut;
+ $$.qualifier = (context->getShaderType() == GL_FRAGMENT_SHADER) ? EvqFragmentOut : EvqCentroidOut;
}
| UNIFORM {
if (context->globalErrorCheck(@1, context->symbolTable.atGlobalLevel(), "uniform"))
@@ -1111,6 +1040,11 @@ type_specifier_no_prec
: type_specifier_nonarray {
$$ = $1;
}
+ | type_specifier_nonarray LEFT_BRACKET RIGHT_BRACKET {
+ ES3_ONLY("[]", @2, "implicitly sized array");
+ $$ = $1;
+ $$.setArraySize(0);
+ }
| type_specifier_nonarray LEFT_BRACKET constant_expression RIGHT_BRACKET {
$$ = $1;
@@ -1120,7 +1054,7 @@ type_specifier_no_prec
int size;
if (context->arraySizeErrorCheck(@2, $3, size))
context->recover();
- $$.setArray(true, size);
+ $$.setArraySize(size);
}
}
;
@@ -1509,9 +1443,9 @@ selection_rest_statement
;
switch_statement
- : SWITCH LEFT_PAREN expression RIGHT_PAREN { ++context->mSwitchNestingLevel; } compound_statement {
+ : SWITCH LEFT_PAREN expression RIGHT_PAREN { context->incrSwitchNestingLevel(); } compound_statement {
$$ = context->addSwitch($3, $6, @1);
- --context->mSwitchNestingLevel;
+ context->decrSwitchNestingLevel();
}
;
@@ -1532,13 +1466,11 @@ condition
context->recover();
}
| fully_specified_type identifier EQUAL initializer {
- TIntermNode* intermNode;
- if (context->structQualifierErrorCheck(@2, $1))
- context->recover();
+ TIntermNode *intermNode;
if (context->boolErrorCheck(@2, $1))
context->recover();
- if (!context->executeInitializer(@2, *$2.string, $1, $4, intermNode))
+ if (!context->executeInitializer(@2, *$2.string, $1, $4, &intermNode))
$$ = $4;
else {
context->recover();
@@ -1548,22 +1480,22 @@ condition
;
iteration_statement
- : WHILE LEFT_PAREN { context->symbolTable.push(); ++context->mLoopNestingLevel; } condition RIGHT_PAREN statement_no_new_scope {
+ : WHILE LEFT_PAREN { context->symbolTable.push(); context->incrLoopNestingLevel(); } condition RIGHT_PAREN statement_no_new_scope {
context->symbolTable.pop();
$$ = context->intermediate.addLoop(ELoopWhile, 0, $4, 0, $6, @1);
- --context->mLoopNestingLevel;
+ context->decrLoopNestingLevel();
}
- | DO { ++context->mLoopNestingLevel; } statement_with_scope WHILE LEFT_PAREN expression RIGHT_PAREN SEMICOLON {
+ | DO { context->incrLoopNestingLevel(); } statement_with_scope WHILE LEFT_PAREN expression RIGHT_PAREN SEMICOLON {
if (context->boolErrorCheck(@8, $6))
context->recover();
$$ = context->intermediate.addLoop(ELoopDoWhile, 0, $6, 0, $3, @4);
- --context->mLoopNestingLevel;
+ context->decrLoopNestingLevel();
}
- | FOR LEFT_PAREN { context->symbolTable.push(); ++context->mLoopNestingLevel; } for_init_statement for_rest_statement RIGHT_PAREN statement_no_new_scope {
+ | FOR LEFT_PAREN { context->symbolTable.push(); context->incrLoopNestingLevel(); } for_init_statement for_rest_statement RIGHT_PAREN statement_no_new_scope {
context->symbolTable.pop();
$$ = context->intermediate.addLoop(ELoopFor, $4, reinterpret_cast<TIntermTyped*>($5.node1), reinterpret_cast<TIntermTyped*>($5.node2), $7, @1);
- --context->mLoopNestingLevel;
+ context->decrLoopNestingLevel();
}
;
@@ -1620,11 +1552,11 @@ jump_statement
translation_unit
: external_declaration {
$$ = $1;
- context->treeRoot = $$;
+ context->setTreeRoot($$);
}
| translation_unit external_declaration {
$$ = context->intermediate.growAggregate($1, $2, @$);
- context->treeRoot = $$;
+ context->setTreeRoot($$);
}
;
@@ -1639,114 +1571,15 @@ external_declaration
function_definition
: function_prototype {
- TFunction* function = $1.function;
-
- const TSymbol *builtIn = context->symbolTable.findBuiltIn(function->getMangledName(), context->shaderVersion);
-
- if (builtIn)
- {
- context->error(@1, "built-in functions cannot be redefined", function->getName().c_str());
- context->recover();
- }
-
- TFunction* prevDec = static_cast<TFunction*>(context->symbolTable.find(function->getMangledName(), context->shaderVersion));
- //
- // Note: 'prevDec' could be 'function' if this is the first time we've seen function
- // as it would have just been put in the symbol table. Otherwise, we're looking up
- // an earlier occurance.
- //
- if (prevDec->isDefined()) {
- //
- // Then this function already has a body.
- //
- context->error(@1, "function already has a body", function->getName().c_str());
- context->recover();
- }
- prevDec->setDefined();
-
- //
- // Raise error message if main function takes any parameters or return anything other than void
- //
- if (function->getName() == "main") {
- if (function->getParamCount() > 0) {
- context->error(@1, "function cannot take any parameter(s)", function->getName().c_str());
- context->recover();
- }
- if (function->getReturnType().getBasicType() != EbtVoid) {
- context->error(@1, "", function->getReturnType().getBasicString(), "main function cannot return a value");
- context->recover();
- }
- }
-
- //
- // Remember the return type for later checking for RETURN statements.
- //
- context->currentFunctionType = &(prevDec->getReturnType());
- context->mFunctionReturnsValue = false;
-
- //
- // Insert parameters into the symbol table.
- // If the parameter has no name, it's not an error, just don't insert it
- // (could be used for unused args).
- //
- // Also, accumulate the list of parameters into the HIL, so lower level code
- // knows where to find parameters.
- //
- TIntermAggregate* paramNodes = new TIntermAggregate;
- for (size_t i = 0; i < function->getParamCount(); i++) {
- const TParameter& param = function->getParam(i);
- if (param.name != 0) {
- TVariable *variable = new TVariable(param.name, *param.type);
- //
- // Insert the parameters with name in the symbol table.
- //
- if (! context->symbolTable.declare(variable)) {
- context->error(@1, "redefinition", variable->getName().c_str());
- context->recover();
- delete variable;
- }
-
- //
- // Add the parameter to the HIL
- //
- paramNodes = context->intermediate.growAggregate(
- paramNodes,
- context->intermediate.addSymbol(variable->getUniqueId(),
- variable->getName(),
- variable->getType(), @1),
- @1);
- } else {
- paramNodes = context->intermediate.growAggregate(paramNodes, context->intermediate.addSymbol(0, "", *param.type, @1), @1);
- }
- }
- context->intermediate.setAggregateOperator(paramNodes, EOpParameters, @1);
- $1.intermAggregate = paramNodes;
- context->mLoopNestingLevel = 0;
+ context->parseFunctionPrototype(@1, $1.function, &$1.intermAggregate);
}
compound_statement_no_new_scope {
- //?? Check that all paths return a value if return type != void ?
- // May be best done as post process phase on intermediate code
- if (context->currentFunctionType->getBasicType() != EbtVoid && ! context->mFunctionReturnsValue) {
- context->error(@1, "function does not return a value:", "", $1.function->getName().c_str());
- context->recover();
- }
-
- $$ = context->intermediate.growAggregate($1.intermAggregate, $3, @$);
- context->intermediate.setAggregateOperator($$, EOpFunction, @1);
- $$->getAsAggregate()->setName($1.function->getMangledName().c_str());
- $$->getAsAggregate()->setType($1.function->getReturnType());
-
- // store the pragma information for debug and optimize and other vendor specific
- // information. This information can be queried from the parse tree
- $$->getAsAggregate()->setOptimize(context->pragma().optimize);
- $$->getAsAggregate()->setDebug(context->pragma().debug);
-
- context->symbolTable.pop();
+ $$ = context->addFunctionDefinition(*($1.function), $1.intermAggregate, $3, @1);
}
;
%%
int glslang_parse(TParseContext* context) {
- return yyparse(context, context->scanner);
+ return yyparse(context, context->getScanner());
}
diff --git a/src/3rdparty/angle/src/compiler/translator/intermOut.cpp b/src/3rdparty/angle/src/compiler/translator/intermOut.cpp
index 07c50f0ce5..6dca547f08 100644
--- a/src/3rdparty/angle/src/compiler/translator/intermOut.cpp
+++ b/src/3rdparty/angle/src/compiler/translator/intermOut.cpp
@@ -10,6 +10,12 @@
namespace
{
+void OutputFunction(TInfoSinkBase &out, const char *str, TIntermAggregate *node)
+{
+ const char *internal = node->getNameObj().isInternal() ? " (internal function)" : "";
+ out << str << internal << ": " << node->getNameObj().getString();
+}
+
//
// Two purposes:
// 1. Show an example of how to iterate tree. Functions can
@@ -27,18 +33,21 @@ class TOutputTraverser : public TIntermTraverser
{
public:
TOutputTraverser(TInfoSinkBase &i)
- : sink(i) { }
+ : TIntermTraverser(true, false, false),
+ sink(i)
+ {
+ }
TInfoSinkBase& sink;
protected:
- void visitSymbol(TIntermSymbol *);
- void visitConstantUnion(TIntermConstantUnion *);
- bool visitBinary(Visit visit, TIntermBinary *);
- bool visitUnary(Visit visit, TIntermUnary *);
- bool visitSelection(Visit visit, TIntermSelection *);
- bool visitAggregate(Visit visit, TIntermAggregate *);
- bool visitLoop(Visit visit, TIntermLoop *);
- bool visitBranch(Visit visit, TIntermBranch *);
+ void visitSymbol(TIntermSymbol *) override;
+ void visitConstantUnion(TIntermConstantUnion *) override;
+ bool visitBinary(Visit visit, TIntermBinary *) override;
+ bool visitUnary(Visit visit, TIntermUnary *) override;
+ bool visitSelection(Visit visit, TIntermSelection *) override;
+ bool visitAggregate(Visit visit, TIntermAggregate *) override;
+ bool visitLoop(Visit visit, TIntermLoop *) override;
+ bool visitBranch(Visit visit, TIntermBranch *) override;
};
//
@@ -56,26 +65,6 @@ void OutputTreeText(TInfoSinkBase &sink, TIntermNode *node, const int depth)
} // namespace anonymous
-
-TString TType::getCompleteString() const
-{
- TStringStream stream;
-
- if (qualifier != EvqTemporary && qualifier != EvqGlobal)
- stream << getQualifierString() << " ";
- if (precision != EbpUndefined)
- stream << getPrecisionString() << " ";
- if (array)
- stream << "array[" << getArraySize() << "] of ";
- if (isMatrix())
- stream << getCols() << "X" << getRows() << " matrix of ";
- else if (isVector())
- stream << getNominalSize() << "-component vector of ";
-
- stream << getBasicString();
- return stream.str();
-}
-
//
// The rest of the file are the traversal functions. The last one
// is the one that starts the traversal.
@@ -265,7 +254,7 @@ bool TOutputTraverser::visitBinary(Visit visit, TIntermBinary *node)
OutputTreeText(out, intermConstantUnion, mDepth + 1);
// The following code finds the field name from the constant union
- const ConstantUnion *constantUnion = intermConstantUnion->getUnionArrayPointer();
+ const TConstantUnion *constantUnion = intermConstantUnion->getUnionArrayPointer();
const TStructure *structure = node->getLeft()->getType().getStruct();
const TInterfaceBlock *interfaceBlock = node->getLeft()->getType().getInterfaceBlock();
ASSERT(structure || interfaceBlock);
@@ -390,10 +379,10 @@ bool TOutputTraverser::visitAggregate(Visit visit, TIntermAggregate *node)
{
case EOpSequence: out << "Sequence\n"; return true;
case EOpComma: out << "Comma\n"; return true;
- case EOpFunction: out << "Function Definition: " << node->getName(); break;
- case EOpFunctionCall: out << "Function Call: " << node->getName(); break;
+ case EOpFunction: OutputFunction(out, "Function Definition", node); break;
+ case EOpFunctionCall: OutputFunction(out, "Function Call", node); break;
case EOpParameters: out << "Function Parameters: "; break;
- case EOpPrototype: out << "Function Prototype: " << node->getName(); break;
+ case EOpPrototype: OutputFunction(out, "Function Prototype", node); break;
case EOpConstructFloat: out << "Construct float"; break;
case EOpConstructVec2: out << "Construct vec2"; break;
@@ -412,7 +401,13 @@ bool TOutputTraverser::visitAggregate(Visit visit, TIntermAggregate *node)
case EOpConstructUVec3: out << "Construct uvec3"; break;
case EOpConstructUVec4: out << "Construct uvec4"; break;
case EOpConstructMat2: out << "Construct mat2"; break;
+ case EOpConstructMat2x3: out << "Construct mat2x3"; break;
+ case EOpConstructMat2x4: out << "Construct mat2x4"; break;
+ case EOpConstructMat3x2: out << "Construct mat3x2"; break;
case EOpConstructMat3: out << "Construct mat3"; break;
+ case EOpConstructMat3x4: out << "Construct mat3x4"; break;
+ case EOpConstructMat4x2: out << "Construct mat4x2"; break;
+ case EOpConstructMat4x3: out << "Construct mat4x3"; break;
case EOpConstructMat4: out << "Construct mat4"; break;
case EOpConstructStruct: out << "Construct structure"; break;
diff --git a/src/3rdparty/angle/src/compiler/translator/timing/RestrictFragmentShaderTiming.cpp b/src/3rdparty/angle/src/compiler/translator/timing/RestrictFragmentShaderTiming.cpp
index 48d44c72d1..790974a2bf 100644
--- a/src/3rdparty/angle/src/compiler/translator/timing/RestrictFragmentShaderTiming.cpp
+++ b/src/3rdparty/angle/src/compiler/translator/timing/RestrictFragmentShaderTiming.cpp
@@ -54,11 +54,8 @@ void RestrictFragmentShaderTiming::enforceRestrictions(const TDependencyGraph& g
// Starting from each sampler, traverse the dependency graph and generate an error each time we
// hit a node where sampler dependent values are not allowed.
- for (TGraphSymbolVector::const_iterator iter = graph.beginSamplerSymbols();
- iter != graph.endSamplerSymbols();
- ++iter)
+ for (auto samplerSymbol : graph.samplerSymbols())
{
- TGraphSymbol* samplerSymbol = *iter;
clearVisited();
samplerSymbol->traverse(this);
}
@@ -66,11 +63,8 @@ void RestrictFragmentShaderTiming::enforceRestrictions(const TDependencyGraph& g
void RestrictFragmentShaderTiming::validateUserDefinedFunctionCallUsage(const TDependencyGraph& graph)
{
- for (TFunctionCallVector::const_iterator iter = graph.beginUserDefinedFunctionCalls();
- iter != graph.endUserDefinedFunctionCalls();
- ++iter)
+ for (const auto* functionCall : graph.userDefinedFunctionCalls())
{
- TGraphFunctionCall* functionCall = *iter;
beginError(functionCall->getIntermFunctionCall());
mSink << "A call to a user defined function is not permitted.\n";
}
diff --git a/src/3rdparty/angle/src/compiler/translator/timing/RestrictVertexShaderTiming.h b/src/3rdparty/angle/src/compiler/translator/timing/RestrictVertexShaderTiming.h
index 74bfd0b5c2..23a8217722 100644
--- a/src/3rdparty/angle/src/compiler/translator/timing/RestrictVertexShaderTiming.h
+++ b/src/3rdparty/angle/src/compiler/translator/timing/RestrictVertexShaderTiming.h
@@ -22,7 +22,8 @@ public:
void enforceRestrictions(TIntermNode* root) { root->traverse(this); }
int numErrors() { return mNumErrors; }
- virtual void visitSymbol(TIntermSymbol*);
+ void visitSymbol(TIntermSymbol *) override;
+
private:
TInfoSinkBase& mSink;
int mNumErrors;
diff --git a/src/3rdparty/angle/src/compiler/translator/util.cpp b/src/3rdparty/angle/src/compiler/translator/util.cpp
index 42a995ee6f..0131137206 100644
--- a/src/3rdparty/angle/src/compiler/translator/util.cpp
+++ b/src/3rdparty/angle/src/compiler/translator/util.cpp
@@ -12,7 +12,7 @@
#include "compiler/translator/SymbolTable.h"
#include "common/utilities.h"
-bool atof_clamp(const char *str, float *value)
+bool strtof_clamp(const std::string &str, float *value)
{
bool success = pp::numeric_lex_float(str, value);
if (!success)
@@ -20,11 +20,11 @@ bool atof_clamp(const char *str, float *value)
return success;
}
-bool atoi_clamp(const char *str, int *value)
+bool atoi_clamp(const char *str, unsigned int *value)
{
bool success = pp::numeric_lex_int(str, value);
if (!success)
- *value = std::numeric_limits<int>::max();
+ *value = std::numeric_limits<unsigned int>::max();
return success;
}
@@ -219,7 +219,6 @@ bool IsVaryingOut(TQualifier qualifier)
switch (qualifier)
{
case EvqVaryingOut:
- case EvqInvariantVaryingOut:
case EvqSmoothOut:
case EvqFlatOut:
case EvqCentroidOut:
@@ -237,7 +236,6 @@ bool IsVaryingIn(TQualifier qualifier)
switch (qualifier)
{
case EvqVaryingIn:
- case EvqInvariantVaryingIn:
case EvqSmoothIn:
case EvqFlatIn:
case EvqCentroidIn:
@@ -269,8 +267,6 @@ InterpolationType GetInterpolationType(TQualifier qualifier)
case EvqFragmentIn:
case EvqVaryingIn:
case EvqVaryingOut:
- case EvqInvariantVaryingIn:
- case EvqInvariantVaryingOut:
return INTERPOLATION_SMOOTH;
case EvqCentroidIn:
@@ -301,13 +297,13 @@ void GetVariableTraverser::setTypeSpecificInfo(
ASSERT(variable);
switch (type.getQualifier())
{
- case EvqInvariantVaryingIn:
- case EvqInvariantVaryingOut:
- variable->isInvariant = true;
- break;
case EvqVaryingIn:
case EvqVaryingOut:
- if (mSymbolTable.isVaryingInvariant(std::string(name.c_str())))
+ case EvqVertexOut:
+ case EvqSmoothOut:
+ case EvqFlatOut:
+ case EvqCentroidOut:
+ if (mSymbolTable.isVaryingInvariant(std::string(name.c_str())) || type.isInvariant())
{
variable->isInvariant = true;
}
diff --git a/src/3rdparty/angle/src/compiler/translator/util.h b/src/3rdparty/angle/src/compiler/translator/util.h
index 68bae66168..ea7a35a352 100644
--- a/src/3rdparty/angle/src/compiler/translator/util.h
+++ b/src/3rdparty/angle/src/compiler/translator/util.h
@@ -14,15 +14,15 @@
#include "compiler/translator/Types.h"
-// atof_clamp is like atof but
+// strtof_clamp is like strtof but
// 1. it forces C locale, i.e. forcing '.' as decimal point.
// 2. it clamps the value to -FLT_MAX or FLT_MAX if overflow happens.
// Return false if overflow happens.
-extern bool atof_clamp(const char *str, float *value);
+bool strtof_clamp(const std::string &str, float *value);
-// If overflow happens, clamp the value to INT_MIN or INT_MAX.
+// If overflow happens, clamp the value to UINT_MIN or UINT_MAX.
// Return false if overflow happens.
-extern bool atoi_clamp(const char *str, int *value);
+bool atoi_clamp(const char *str, unsigned int *value);
class TSymbolTable;
@@ -41,6 +41,7 @@ class GetVariableTraverser : angle::NonCopyable
{
public:
GetVariableTraverser(const TSymbolTable &symbolTable);
+ virtual ~GetVariableTraverser() {}
template <typename VarT>
void traverse(const TType &type, const TString &name, std::vector<VarT> *output);
diff --git a/src/3rdparty/angle/src/id/commit.h b/src/3rdparty/angle/src/id/commit.h
index fd9a011d0c..0546412964 100644
--- a/src/3rdparty/angle/src/id/commit.h
+++ b/src/3rdparty/angle/src/id/commit.h
@@ -1,3 +1,3 @@
-#define ANGLE_COMMIT_HASH "99f075dade7c"
+#define ANGLE_COMMIT_HASH "8613f4946861"
#define ANGLE_COMMIT_HASH_SIZE 12
-#define ANGLE_COMMIT_DATE "2015-04-02 17:07:24 +0000"
+#define ANGLE_COMMIT_DATE "2016-02-11 19:53:41 +0000"
diff --git a/src/3rdparty/angle/src/libANGLE/AttributeMap.h b/src/3rdparty/angle/src/libANGLE/AttributeMap.h
index 72b6edc3c7..56f1684415 100644
--- a/src/3rdparty/angle/src/libANGLE/AttributeMap.h
+++ b/src/3rdparty/angle/src/libANGLE/AttributeMap.h
@@ -15,15 +15,15 @@
namespace egl
{
-class AttributeMap
+class AttributeMap final
{
public:
AttributeMap();
explicit AttributeMap(const EGLint *attributes);
- virtual void insert(EGLint key, EGLint value);
- virtual bool contains(EGLint key) const;
- virtual EGLint get(EGLint key, EGLint defaultValue) const;
+ void insert(EGLint key, EGLint value);
+ bool contains(EGLint key) const;
+ EGLint get(EGLint key, EGLint defaultValue) const;
typedef std::map<EGLint, EGLint>::const_iterator const_iterator;
diff --git a/src/3rdparty/angle/src/libANGLE/BinaryStream.h b/src/3rdparty/angle/src/libANGLE/BinaryStream.h
index 50392e1d3f..3e6ccc7446 100644
--- a/src/3rdparty/angle/src/libANGLE/BinaryStream.h
+++ b/src/3rdparty/angle/src/libANGLE/BinaryStream.h
@@ -47,7 +47,7 @@ class BinaryInputStream : angle::NonCopyable
template <class IntT>
IntT readInt()
{
- int value;
+ int value = 0;
read(&value);
return static_cast<IntT>(value);
}
@@ -60,7 +60,7 @@ class BinaryInputStream : angle::NonCopyable
bool readBool()
{
- int value;
+ int value = 0;
read(&value);
return (value > 0);
}
@@ -92,7 +92,7 @@ class BinaryInputStream : angle::NonCopyable
return;
}
- if (mOffset + length > mLength)
+ if (!rx::IsUnsignedAdditionSafe(mOffset, length) || mOffset + length > mLength)
{
mError = true;
return;
@@ -104,7 +104,7 @@ class BinaryInputStream : angle::NonCopyable
void skip(size_t length)
{
- if (mOffset + length > mLength)
+ if (!rx::IsUnsignedAdditionSafe(mOffset, length) || mOffset + length > mLength)
{
mError = true;
return;
@@ -144,9 +144,15 @@ class BinaryInputStream : angle::NonCopyable
{
StaticAssertIsFundamental<T>();
+ if (!rx::IsUnsignedMultiplicationSafe(num, sizeof(T)))
+ {
+ mError = true;
+ return;
+ }
+
size_t length = num * sizeof(T);
- if (mOffset + length > mLength)
+ if (!rx::IsUnsignedAdditionSafe(mOffset, length) || mOffset + length > mLength)
{
mError = true;
return;
diff --git a/src/3rdparty/angle/src/libANGLE/Buffer.cpp b/src/3rdparty/angle/src/libANGLE/Buffer.cpp
index f394a6b1d1..589735c5a8 100644
--- a/src/3rdparty/angle/src/libANGLE/Buffer.cpp
+++ b/src/3rdparty/angle/src/libANGLE/Buffer.cpp
@@ -18,9 +18,11 @@ namespace gl
Buffer::Buffer(rx::BufferImpl *impl, GLuint id)
: RefCountObject(id),
mBuffer(impl),
- mUsage(GL_DYNAMIC_DRAW),
+ mLabel(),
+ mUsage(GL_STATIC_DRAW),
mSize(0),
mAccessFlags(0),
+ mAccess(GL_WRITE_ONLY_OES),
mMapped(GL_FALSE),
mMapPointer(NULL),
mMapOffset(0),
@@ -33,6 +35,16 @@ Buffer::~Buffer()
SafeDelete(mBuffer);
}
+void Buffer::setLabel(const std::string &label)
+{
+ mLabel = label;
+}
+
+const std::string &Buffer::getLabel() const
+{
+ return mLabel;
+}
+
Error Buffer::bufferData(const void *data, GLsizeiptr size, GLenum usage)
{
gl::Error error = mBuffer->setData(data, size, usage);
@@ -56,7 +68,7 @@ Error Buffer::bufferSubData(const void *data, GLsizeiptr size, GLintptr offset)
return error;
}
- mIndexRangeCache.invalidateRange(offset, size);
+ mIndexRangeCache.invalidateRange(static_cast<unsigned int>(offset), static_cast<unsigned int>(size));
return error;
}
@@ -69,7 +81,30 @@ Error Buffer::copyBufferSubData(Buffer* source, GLintptr sourceOffset, GLintptr
return error;
}
- mIndexRangeCache.invalidateRange(destOffset, size);
+ mIndexRangeCache.invalidateRange(static_cast<unsigned int>(destOffset), static_cast<unsigned int>(size));
+
+ return error;
+}
+
+Error Buffer::map(GLenum access)
+{
+ ASSERT(!mMapped);
+
+ Error error = mBuffer->map(access, &mMapPointer);
+ if (error.isError())
+ {
+ mMapPointer = NULL;
+ return error;
+ }
+
+ ASSERT(access == GL_WRITE_ONLY_OES);
+
+ mMapped = GL_TRUE;
+ mMapOffset = 0;
+ mMapLength = mSize;
+ mAccess = access;
+ mAccessFlags = GL_MAP_WRITE_BIT;
+ mIndexRangeCache.clear();
return error;
}
@@ -79,7 +114,7 @@ Error Buffer::mapRange(GLintptr offset, GLsizeiptr length, GLbitfield access)
ASSERT(!mMapped);
ASSERT(offset + length <= mSize);
- Error error = mBuffer->map(offset, length, access, &mMapPointer);
+ Error error = mBuffer->mapRange(offset, length, access, &mMapPointer);
if (error.isError())
{
mMapPointer = NULL;
@@ -89,23 +124,30 @@ Error Buffer::mapRange(GLintptr offset, GLsizeiptr length, GLbitfield access)
mMapped = GL_TRUE;
mMapOffset = static_cast<GLint64>(offset);
mMapLength = static_cast<GLint64>(length);
- mAccessFlags = static_cast<GLint>(access);
+ mAccess = GL_WRITE_ONLY_OES;
+ mAccessFlags = access;
+
+ // The OES_mapbuffer extension states that GL_WRITE_ONLY_OES is the only valid
+ // value for GL_BUFFER_ACCESS_OES because it was written against ES2. Since there is
+ // no update for ES3 and the GL_READ_ONLY and GL_READ_WRITE enums don't exist for ES,
+ // we cannot properly set GL_BUFFER_ACCESS_OES when glMapBufferRange is called.
if ((access & GL_MAP_WRITE_BIT) > 0)
{
- mIndexRangeCache.invalidateRange(offset, length);
+ mIndexRangeCache.invalidateRange(static_cast<unsigned int>(offset), static_cast<unsigned int>(length));
}
return error;
}
-Error Buffer::unmap()
+Error Buffer::unmap(GLboolean *result)
{
ASSERT(mMapped);
- Error error = mBuffer->unmap();
+ Error error = mBuffer->unmap(result);
if (error.isError())
{
+ *result = GL_FALSE;
return error;
}
@@ -113,9 +155,42 @@ Error Buffer::unmap()
mMapPointer = NULL;
mMapOffset = 0;
mMapLength = 0;
+ mAccess = GL_WRITE_ONLY_OES;
mAccessFlags = 0;
return error;
}
+void Buffer::onTransformFeedback()
+{
+ mIndexRangeCache.clear();
+}
+
+void Buffer::onPixelUnpack()
+{
+ mIndexRangeCache.clear();
+}
+
+Error Buffer::getIndexRange(GLenum type,
+ size_t offset,
+ size_t count,
+ bool primitiveRestartEnabled,
+ IndexRange *outRange) const
+{
+ if (mIndexRangeCache.findRange(type, offset, count, primitiveRestartEnabled, outRange))
+ {
+ return gl::Error(GL_NO_ERROR);
+ }
+
+ Error error = mBuffer->getIndexRange(type, offset, count, primitiveRestartEnabled, outRange);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ mIndexRangeCache.addRange(type, offset, count, primitiveRestartEnabled, *outRange);
+
+ return Error(GL_NO_ERROR);
+}
+
}
diff --git a/src/3rdparty/angle/src/libANGLE/Buffer.h b/src/3rdparty/angle/src/libANGLE/Buffer.h
index 6793028e3b..6c951ef586 100644
--- a/src/3rdparty/angle/src/libANGLE/Buffer.h
+++ b/src/3rdparty/angle/src/libANGLE/Buffer.h
@@ -11,11 +11,11 @@
#ifndef LIBANGLE_BUFFER_H_
#define LIBANGLE_BUFFER_H_
+#include "common/angleutils.h"
+#include "libANGLE/Debug.h"
#include "libANGLE/Error.h"
+#include "libANGLE/IndexRangeCache.h"
#include "libANGLE/RefCountObject.h"
-#include "libANGLE/renderer/IndexRangeCache.h"
-
-#include "common/angleutils.h"
namespace rx
{
@@ -25,21 +25,34 @@ class BufferImpl;
namespace gl
{
-class Buffer : public RefCountObject
+class Buffer final : public RefCountObject, public LabeledObject
{
public:
Buffer(rx::BufferImpl *impl, GLuint id);
-
virtual ~Buffer();
+ void setLabel(const std::string &label) override;
+ const std::string &getLabel() const override;
+
Error bufferData(const void *data, GLsizeiptr size, GLenum usage);
Error bufferSubData(const void *data, GLsizeiptr size, GLintptr offset);
Error copyBufferSubData(Buffer* source, GLintptr sourceOffset, GLintptr destOffset, GLsizeiptr size);
+ Error map(GLenum access);
Error mapRange(GLintptr offset, GLsizeiptr length, GLbitfield access);
- Error unmap();
+ Error unmap(GLboolean *result);
+
+ void onTransformFeedback();
+ void onPixelUnpack();
+
+ Error getIndexRange(GLenum type,
+ size_t offset,
+ size_t count,
+ bool primitiveRestartEnabled,
+ IndexRange *outRange) const;
GLenum getUsage() const { return mUsage; }
- GLint getAccessFlags() const { return mAccessFlags; }
+ GLbitfield getAccessFlags() const { return mAccessFlags; }
+ GLenum getAccess() const { return mAccess; }
GLboolean isMapped() const { return mMapped; }
GLvoid *getMapPointer() const { return mMapPointer; }
GLint64 getMapOffset() const { return mMapOffset; }
@@ -48,21 +61,21 @@ class Buffer : public RefCountObject
rx::BufferImpl *getImplementation() const { return mBuffer; }
- rx::IndexRangeCache *getIndexRangeCache() { return &mIndexRangeCache; }
- const rx::IndexRangeCache *getIndexRangeCache() const { return &mIndexRangeCache; }
-
private:
rx::BufferImpl *mBuffer;
+ std::string mLabel;
+
GLenum mUsage;
GLint64 mSize;
- GLint mAccessFlags;
+ GLbitfield mAccessFlags;
+ GLenum mAccess;
GLboolean mMapped;
GLvoid *mMapPointer;
GLint64 mMapOffset;
GLint64 mMapLength;
- rx::IndexRangeCache mIndexRangeCache;
+ mutable IndexRangeCache mIndexRangeCache;
};
}
diff --git a/src/3rdparty/angle/src/libANGLE/Caps.cpp b/src/3rdparty/angle/src/libANGLE/Caps.cpp
index 086d0a02a2..1eb54a1589 100644
--- a/src/3rdparty/angle/src/libANGLE/Caps.cpp
+++ b/src/3rdparty/angle/src/libANGLE/Caps.cpp
@@ -58,7 +58,7 @@ GLuint TextureCaps::getNearestSamples(GLuint requestedSamples) const
void TextureCapsMap::insert(GLenum internalFormat, const TextureCaps &caps)
{
- mCapsMap.insert(std::make_pair(internalFormat, caps));
+ mCapsMap[internalFormat] = caps;
}
void TextureCapsMap::remove(GLenum internalFormat)
@@ -102,6 +102,7 @@ Extensions::Extensions()
pixelBufferObject(false),
mapBuffer(false),
mapBufferRange(false),
+ colorBufferHalfFloat(false),
textureHalfFloat(false),
textureHalfFloatLinear(false),
textureFloat(false),
@@ -110,15 +111,22 @@ Extensions::Extensions()
textureCompressionDXT1(false),
textureCompressionDXT3(false),
textureCompressionDXT5(false),
+ textureCompressionASTCHDR(false),
+ textureCompressionASTCLDR(false),
+ compressedETC1RGB8Texture(false),
depthTextures(false),
+ depth32(false),
+ textureStorage(false),
textureNPOT(false),
drawBuffers(false),
- textureStorage(false),
textureFilterAnisotropic(false),
maxTextureAnisotropy(false),
occlusionQueryBoolean(false),
fence(false),
timerQuery(false),
+ disjointTimerQuery(false),
+ queryCounterBitsTimeElapsed(0),
+ queryCounterBitsTimestamp(0),
robustness(false),
blendMinMax(false),
framebufferBlit(false),
@@ -133,6 +141,22 @@ Extensions::Extensions()
fragDepth(false),
textureUsage(false),
translatedShaderSource(false),
+ fboRenderMipmap(false),
+ discardFramebuffer(false),
+ debugMarker(false),
+ eglImage(false),
+ eglImageExternal(false),
+ eglImageExternalEssl3(false),
+ unpackSubimage(false),
+ packSubimage(false),
+ vertexArrayObject(false),
+ debug(false),
+ maxDebugMessageLength(0),
+ maxDebugLoggedMessages(0),
+ maxDebugGroupStackDepth(0),
+ maxLabelLength(0),
+ noError(false),
+ lossyETCDecode(false),
colorBufferFloat(false)
{
}
@@ -141,52 +165,84 @@ std::vector<std::string> Extensions::getStrings() const
{
std::vector<std::string> extensionStrings;
- // | Extension name | Supported flag | Output vector |
- InsertExtensionString("GL_OES_element_index_uint", elementIndexUint, &extensionStrings);
- InsertExtensionString("GL_OES_packed_depth_stencil", packedDepthStencil, &extensionStrings);
- InsertExtensionString("GL_OES_get_program_binary", getProgramBinary, &extensionStrings);
- InsertExtensionString("GL_OES_rgb8_rgba8", rgb8rgba8, &extensionStrings);
- InsertExtensionString("GL_EXT_texture_format_BGRA8888", textureFormatBGRA8888, &extensionStrings);
- InsertExtensionString("GL_EXT_read_format_bgra", readFormatBGRA, &extensionStrings);
- InsertExtensionString("GL_NV_pixel_buffer_object", pixelBufferObject, &extensionStrings);
- InsertExtensionString("GL_OES_mapbuffer", mapBuffer, &extensionStrings);
- InsertExtensionString("GL_EXT_map_buffer_range", mapBufferRange, &extensionStrings);
- InsertExtensionString("GL_OES_texture_half_float", textureHalfFloat, &extensionStrings);
- InsertExtensionString("GL_OES_texture_half_float_linear", textureHalfFloatLinear, &extensionStrings);
- InsertExtensionString("GL_OES_texture_float", textureFloat, &extensionStrings);
- InsertExtensionString("GL_OES_texture_float_linear", textureFloatLinear, &extensionStrings);
- InsertExtensionString("GL_EXT_texture_rg", textureRG, &extensionStrings);
- InsertExtensionString("GL_EXT_texture_compression_dxt1", textureCompressionDXT1, &extensionStrings);
- InsertExtensionString("GL_ANGLE_texture_compression_dxt3", textureCompressionDXT3, &extensionStrings);
- InsertExtensionString("GL_ANGLE_texture_compression_dxt5", textureCompressionDXT5, &extensionStrings);
- InsertExtensionString("GL_EXT_sRGB", sRGB, &extensionStrings);
- InsertExtensionString("GL_ANGLE_depth_texture", depthTextures, &extensionStrings);
- InsertExtensionString("GL_EXT_texture_storage", textureStorage, &extensionStrings);
- InsertExtensionString("GL_OES_texture_npot", textureNPOT, &extensionStrings);
- InsertExtensionString("GL_EXT_draw_buffers", drawBuffers, &extensionStrings);
- InsertExtensionString("GL_EXT_texture_filter_anisotropic", textureFilterAnisotropic, &extensionStrings);
- InsertExtensionString("GL_EXT_occlusion_query_boolean", occlusionQueryBoolean, &extensionStrings);
- InsertExtensionString("GL_NV_fence", fence, &extensionStrings);
- InsertExtensionString("GL_ANGLE_timer_query", timerQuery, &extensionStrings);
- InsertExtensionString("GL_EXT_robustness", robustness, &extensionStrings);
- InsertExtensionString("GL_EXT_blend_minmax", blendMinMax, &extensionStrings);
- InsertExtensionString("GL_ANGLE_framebuffer_blit", framebufferBlit, &extensionStrings);
- InsertExtensionString("GL_ANGLE_framebuffer_multisample", framebufferMultisample, &extensionStrings);
- InsertExtensionString("GL_ANGLE_instanced_arrays", instancedArrays, &extensionStrings);
- InsertExtensionString("GL_ANGLE_pack_reverse_row_order", packReverseRowOrder, &extensionStrings);
- InsertExtensionString("GL_OES_standard_derivatives", standardDerivatives, &extensionStrings);
- InsertExtensionString("GL_EXT_shader_texture_lod", shaderTextureLOD, &extensionStrings);
- InsertExtensionString("GL_NV_shader_framebuffer_fetch", NVshaderFramebufferFetch, &extensionStrings);
- InsertExtensionString("GL_ARM_shader_framebuffer_fetch", ARMshaderFramebufferFetch,&extensionStrings);
- InsertExtensionString("GL_EXT_shader_framebuffer_fetch", shaderFramebufferFetch, &extensionStrings);
- InsertExtensionString("GL_EXT_frag_depth", fragDepth, &extensionStrings);
- InsertExtensionString("GL_ANGLE_texture_usage", textureUsage, &extensionStrings);
- InsertExtensionString("GL_ANGLE_translated_shader_source", translatedShaderSource, &extensionStrings);
- InsertExtensionString("GL_EXT_color_buffer_float", colorBufferFloat, &extensionStrings);
+ // clang-format off
+ // | Extension name | Supported flag | Output vector |
+ InsertExtensionString("GL_OES_element_index_uint", elementIndexUint, &extensionStrings);
+ InsertExtensionString("GL_OES_packed_depth_stencil", packedDepthStencil, &extensionStrings);
+ InsertExtensionString("GL_OES_get_program_binary", getProgramBinary, &extensionStrings);
+ InsertExtensionString("GL_OES_rgb8_rgba8", rgb8rgba8, &extensionStrings);
+ InsertExtensionString("GL_EXT_texture_format_BGRA8888", textureFormatBGRA8888, &extensionStrings);
+ InsertExtensionString("GL_EXT_read_format_bgra", readFormatBGRA, &extensionStrings);
+ InsertExtensionString("GL_NV_pixel_buffer_object", pixelBufferObject, &extensionStrings);
+ InsertExtensionString("GL_OES_mapbuffer", mapBuffer, &extensionStrings);
+ InsertExtensionString("GL_EXT_map_buffer_range", mapBufferRange, &extensionStrings);
+ InsertExtensionString("GL_EXT_color_buffer_half_float", colorBufferHalfFloat, &extensionStrings);
+ InsertExtensionString("GL_OES_texture_half_float", textureHalfFloat, &extensionStrings);
+ InsertExtensionString("GL_OES_texture_half_float_linear", textureHalfFloatLinear, &extensionStrings);
+ InsertExtensionString("GL_OES_texture_float", textureFloat, &extensionStrings);
+ InsertExtensionString("GL_OES_texture_float_linear", textureFloatLinear, &extensionStrings);
+ InsertExtensionString("GL_EXT_texture_rg", textureRG, &extensionStrings);
+ InsertExtensionString("GL_EXT_texture_compression_dxt1", textureCompressionDXT1, &extensionStrings);
+ InsertExtensionString("GL_ANGLE_texture_compression_dxt3", textureCompressionDXT3, &extensionStrings);
+ InsertExtensionString("GL_ANGLE_texture_compression_dxt5", textureCompressionDXT5, &extensionStrings);
+ InsertExtensionString("GL_KHR_texture_compression_astc_hdr", textureCompressionASTCHDR, &extensionStrings);
+ InsertExtensionString("GL_KHR_texture_compression_astc_ldr", textureCompressionASTCLDR, &extensionStrings);
+ InsertExtensionString("GL_OES_compressed_ETC1_RGB8_texture", compressedETC1RGB8Texture, &extensionStrings);
+ InsertExtensionString("GL_EXT_sRGB", sRGB, &extensionStrings);
+ InsertExtensionString("GL_ANGLE_depth_texture", depthTextures, &extensionStrings);
+ InsertExtensionString("GL_OES_depth32", depth32, &extensionStrings);
+ InsertExtensionString("GL_EXT_texture_storage", textureStorage, &extensionStrings);
+ InsertExtensionString("GL_OES_texture_npot", textureNPOT, &extensionStrings);
+ InsertExtensionString("GL_EXT_draw_buffers", drawBuffers, &extensionStrings);
+ InsertExtensionString("GL_EXT_texture_filter_anisotropic", textureFilterAnisotropic, &extensionStrings);
+ InsertExtensionString("GL_EXT_occlusion_query_boolean", occlusionQueryBoolean, &extensionStrings);
+ InsertExtensionString("GL_NV_fence", fence, &extensionStrings);
+ InsertExtensionString("GL_ANGLE_timer_query", timerQuery, &extensionStrings);
+ InsertExtensionString("GL_EXT_disjoint_timer_query", disjointTimerQuery, &extensionStrings);
+ InsertExtensionString("GL_EXT_robustness", robustness, &extensionStrings);
+ InsertExtensionString("GL_EXT_blend_minmax", blendMinMax, &extensionStrings);
+ InsertExtensionString("GL_ANGLE_framebuffer_blit", framebufferBlit, &extensionStrings);
+ InsertExtensionString("GL_ANGLE_framebuffer_multisample", framebufferMultisample, &extensionStrings);
+ InsertExtensionString("GL_ANGLE_instanced_arrays", instancedArrays, &extensionStrings);
+ InsertExtensionString("GL_ANGLE_pack_reverse_row_order", packReverseRowOrder, &extensionStrings);
+ InsertExtensionString("GL_OES_standard_derivatives", standardDerivatives, &extensionStrings);
+ InsertExtensionString("GL_EXT_shader_texture_lod", shaderTextureLOD, &extensionStrings);
+ InsertExtensionString("GL_NV_shader_framebuffer_fetch", NVshaderFramebufferFetch, &extensionStrings);
+ InsertExtensionString("GL_ARM_shader_framebuffer_fetch", ARMshaderFramebufferFetch, &extensionStrings);
+ InsertExtensionString("GL_EXT_shader_framebuffer_fetch", shaderFramebufferFetch, &extensionStrings);
+ InsertExtensionString("GL_EXT_frag_depth", fragDepth, &extensionStrings);
+ InsertExtensionString("GL_ANGLE_texture_usage", textureUsage, &extensionStrings);
+ InsertExtensionString("GL_ANGLE_translated_shader_source", translatedShaderSource, &extensionStrings);
+ InsertExtensionString("GL_OES_fbo_render_mipmap", fboRenderMipmap, &extensionStrings);
+ InsertExtensionString("GL_EXT_discard_framebuffer", discardFramebuffer, &extensionStrings);
+ InsertExtensionString("GL_EXT_debug_marker", debugMarker, &extensionStrings);
+ InsertExtensionString("GL_OES_EGL_image", eglImage, &extensionStrings);
+ InsertExtensionString("GL_OES_EGL_image_external", eglImageExternal, &extensionStrings);
+ InsertExtensionString("GL_OES_EGL_image_external_essl3", eglImageExternalEssl3, &extensionStrings);
+ InsertExtensionString("GL_EXT_unpack_subimage", unpackSubimage, &extensionStrings);
+ InsertExtensionString("GL_NV_pack_subimage", packSubimage, &extensionStrings);
+ InsertExtensionString("GL_EXT_color_buffer_float", colorBufferFloat, &extensionStrings);
+ InsertExtensionString("GL_OES_vertex_array_object", vertexArrayObject, &extensionStrings);
+ InsertExtensionString("GL_KHR_debug", debug, &extensionStrings);
+ // TODO(jmadill): Enable this when complete.
+ //InsertExtensionString("GL_KHR_no_error", noError, &extensionStrings);
+
+ InsertExtensionString("GL_ANGLE_lossy_etc_decode", lossyETCDecode, &extensionStrings);
+ // clang-format on
return extensionStrings;
}
+Limitations::Limitations()
+ : noFrontFacingSupport(false),
+ noSampleAlphaToCoverageSupport(false),
+ attributeZeroRequiresZeroDivisorInEXT(false),
+ noSeparateStencilRefsAndMasks(false),
+ shadersRequireIndexedLoopValidation(false),
+ noSimultaneousConstantColorAndAlphaBlendFunc(false)
+{
+}
+
static bool GetFormatSupport(const TextureCapsMap &textureCaps, const std::vector<GLenum> &requiredFormats,
bool requiresTexturing, bool requiresFiltering, bool requiresRendering)
{
@@ -213,6 +269,15 @@ static bool GetFormatSupport(const TextureCapsMap &textureCaps, const std::vecto
return true;
}
+// Check for GL_OES_packed_depth_stencil
+static bool DeterminePackedDepthStencilSupport(const TextureCapsMap &textureCaps)
+{
+ std::vector<GLenum> requiredFormats;
+ requiredFormats.push_back(GL_DEPTH24_STENCIL8);
+
+ return GetFormatSupport(textureCaps, requiredFormats, false, false, true);
+}
+
// Checks for GL_OES_rgb8_rgba8 support
static bool DetermineRGB8AndRGBA8TextureSupport(const TextureCapsMap &textureCaps)
{
@@ -232,6 +297,18 @@ static bool DetermineBGRA8TextureSupport(const TextureCapsMap &textureCaps)
return GetFormatSupport(textureCaps, requiredFormats, true, true, true);
}
+// Checks for GL_OES_color_buffer_half_float support
+static bool DetermineColorBufferHalfFloatSupport(const TextureCapsMap &textureCaps)
+{
+ std::vector<GLenum> requiredFormats;
+ requiredFormats.push_back(GL_RGBA16F);
+ requiredFormats.push_back(GL_RGB16F);
+ requiredFormats.push_back(GL_RG16F);
+ requiredFormats.push_back(GL_R16F);
+
+ return GetFormatSupport(textureCaps, requiredFormats, true, false, true);
+}
+
// Checks for GL_OES_texture_half_float support
static bool DetermineHalfFloatTextureSupport(const TextureCapsMap &textureCaps)
{
@@ -249,7 +326,8 @@ static bool DetermineHalfFloatTextureFilteringSupport(const TextureCapsMap &text
requiredFormats.push_back(GL_RGB16F);
requiredFormats.push_back(GL_RGBA16F);
- return GetFormatSupport(textureCaps, requiredFormats, true, true, false);
+ return DetermineHalfFloatTextureSupport(textureCaps) &&
+ GetFormatSupport(textureCaps, requiredFormats, true, true, false);
}
// Checks for GL_OES_texture_float support
@@ -269,7 +347,8 @@ static bool DetermineFloatTextureFilteringSupport(const TextureCapsMap &textureC
requiredFormats.push_back(GL_RGB32F);
requiredFormats.push_back(GL_RGBA32F);
- return GetFormatSupport(textureCaps, requiredFormats, true, true, false);
+ return DetermineFloatTextureSupport(textureCaps) &&
+ GetFormatSupport(textureCaps, requiredFormats, true, true, false);
}
// Checks for GL_EXT_texture_rg support
@@ -320,6 +399,51 @@ static bool DetermineDXT5TextureSupport(const TextureCapsMap &textureCaps)
return GetFormatSupport(textureCaps, requiredFormats, true, true, false);
}
+// Check for GL_KHR_texture_compression_astc_hdr and GL_KHR_texture_compression_astc_ldr
+static bool DetermineASTCTextureSupport(const TextureCapsMap &textureCaps)
+{
+ std::vector<GLenum> requiredFormats;
+ requiredFormats.push_back(GL_COMPRESSED_RGBA_ASTC_4x4_KHR);
+ requiredFormats.push_back(GL_COMPRESSED_RGBA_ASTC_5x4_KHR);
+ requiredFormats.push_back(GL_COMPRESSED_RGBA_ASTC_5x5_KHR);
+ requiredFormats.push_back(GL_COMPRESSED_RGBA_ASTC_6x5_KHR);
+ requiredFormats.push_back(GL_COMPRESSED_RGBA_ASTC_6x6_KHR);
+ requiredFormats.push_back(GL_COMPRESSED_RGBA_ASTC_8x5_KHR);
+ requiredFormats.push_back(GL_COMPRESSED_RGBA_ASTC_8x6_KHR);
+ requiredFormats.push_back(GL_COMPRESSED_RGBA_ASTC_8x8_KHR);
+ requiredFormats.push_back(GL_COMPRESSED_RGBA_ASTC_10x5_KHR);
+ requiredFormats.push_back(GL_COMPRESSED_RGBA_ASTC_10x6_KHR);
+ requiredFormats.push_back(GL_COMPRESSED_RGBA_ASTC_10x8_KHR);
+ requiredFormats.push_back(GL_COMPRESSED_RGBA_ASTC_10x10_KHR);
+ requiredFormats.push_back(GL_COMPRESSED_RGBA_ASTC_12x10_KHR);
+ requiredFormats.push_back(GL_COMPRESSED_RGBA_ASTC_12x12_KHR);
+ requiredFormats.push_back(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR);
+ requiredFormats.push_back(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR);
+ requiredFormats.push_back(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR);
+ requiredFormats.push_back(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR);
+ requiredFormats.push_back(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR);
+ requiredFormats.push_back(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR);
+ requiredFormats.push_back(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR);
+ requiredFormats.push_back(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR);
+ requiredFormats.push_back(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR);
+ requiredFormats.push_back(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR);
+ requiredFormats.push_back(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR);
+ requiredFormats.push_back(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR);
+ requiredFormats.push_back(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR);
+ requiredFormats.push_back(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR);
+
+ return GetFormatSupport(textureCaps, requiredFormats, true, true, false);
+}
+
+// Check for GL_ETC1_RGB8_OES
+static bool DetermineETC1RGB8TextureSupport(const TextureCapsMap &textureCaps)
+{
+ std::vector<GLenum> requiredFormats;
+ requiredFormats.push_back(GL_ETC1_RGB8_OES);
+
+ return GetFormatSupport(textureCaps, requiredFormats, true, true, false);
+}
+
// Check for GL_ANGLE_texture_compression_dxt5
static bool DetermineSRGBTextureSupport(const TextureCapsMap &textureCaps)
{
@@ -345,6 +469,15 @@ static bool DetermineDepthTextureSupport(const TextureCapsMap &textureCaps)
return GetFormatSupport(textureCaps, requiredFormats, true, true, true);
}
+// Check for GL_OES_depth32
+static bool DetermineDepth32Support(const TextureCapsMap &textureCaps)
+{
+ std::vector<GLenum> requiredFormats;
+ requiredFormats.push_back(GL_DEPTH_COMPONENT32_OES);
+
+ return GetFormatSupport(textureCaps, requiredFormats, false, false, true);
+}
+
// Check for GL_EXT_color_buffer_float
static bool DetermineColorBufferFloatSupport(const TextureCapsMap &textureCaps)
{
@@ -362,8 +495,10 @@ static bool DetermineColorBufferFloatSupport(const TextureCapsMap &textureCaps)
void Extensions::setTextureExtensionSupport(const TextureCapsMap &textureCaps)
{
+ packedDepthStencil = DeterminePackedDepthStencilSupport(textureCaps);
rgb8rgba8 = DetermineRGB8AndRGBA8TextureSupport(textureCaps);
textureFormatBGRA8888 = DetermineBGRA8TextureSupport(textureCaps);
+ colorBufferHalfFloat = DetermineColorBufferHalfFloatSupport(textureCaps);
textureHalfFloat = DetermineHalfFloatTextureSupport(textureCaps);
textureHalfFloatLinear = DetermineHalfFloatTextureFilteringSupport(textureCaps);
textureFloat = DetermineFloatTextureSupport(textureCaps);
@@ -372,8 +507,12 @@ void Extensions::setTextureExtensionSupport(const TextureCapsMap &textureCaps)
textureCompressionDXT1 = DetermineDXT1TextureSupport(textureCaps);
textureCompressionDXT3 = DetermineDXT3TextureSupport(textureCaps);
textureCompressionDXT5 = DetermineDXT5TextureSupport(textureCaps);
+ textureCompressionASTCHDR = DetermineASTCTextureSupport(textureCaps);
+ textureCompressionASTCLDR = textureCompressionASTCHDR;
+ compressedETC1RGB8Texture = DetermineETC1RGB8TextureSupport(textureCaps);
sRGB = DetermineSRGBTextureSupport(textureCaps);
depthTextures = DetermineDepthTextureSupport(textureCaps);
+ depth32 = DetermineDepth32Support(textureCaps);
colorBufferFloat = DetermineColorBufferFloatSupport(textureCaps);
}
@@ -446,7 +585,7 @@ Caps::Caps()
maxTextureImageUnits(0),
minProgramTexelOffset(0),
maxProgramTexelOffset(0),
-
+ // Table 6.33
maxUniformBufferBindings(0),
maxUniformBlockSize(0),
uniformBufferOffsetAlignment(0),
@@ -456,10 +595,12 @@ Caps::Caps()
maxVaryingComponents(0),
maxVaryingVectors(0),
maxCombinedTextureImageUnits(0),
-
+ // Table 6.34
maxTransformFeedbackInterleavedComponents(0),
maxTransformFeedbackSeparateAttributes(0),
- maxTransformFeedbackSeparateComponents(0)
+ maxTransformFeedbackSeparateComponents(0),
+ // Table 6.35
+ maxSamples(0)
{
}
@@ -479,8 +620,22 @@ DisplayExtensions::DisplayExtensions()
surfaceD3DTexture2DShareHandle(false),
querySurfacePointer(false),
windowFixedSize(false),
+ keyedMutex(false),
+ surfaceOrientation(false),
postSubBuffer(false),
- createContext(false)
+ createContext(false),
+ deviceQuery(false),
+ image(false),
+ imageBase(false),
+ imagePixmap(false),
+ glTexture2DImage(false),
+ glTextureCubemapImage(false),
+ glTexture3DImage(false),
+ glRenderbufferImage(false),
+ getAllProcAddresses(false),
+ flexibleSurfaceCompatibility(false),
+ directComposition(false),
+ createContextNoError(false)
{
}
@@ -488,25 +643,62 @@ std::vector<std::string> DisplayExtensions::getStrings() const
{
std::vector<std::string> extensionStrings;
+ // clang-format off
// | Extension name | Supported flag | Output vector |
InsertExtensionString("EGL_EXT_create_context_robustness", createContextRobustness, &extensionStrings);
InsertExtensionString("EGL_ANGLE_d3d_share_handle_client_buffer", d3dShareHandleClientBuffer, &extensionStrings);
InsertExtensionString("EGL_ANGLE_surface_d3d_texture_2d_share_handle", surfaceD3DTexture2DShareHandle, &extensionStrings);
InsertExtensionString("EGL_ANGLE_query_surface_pointer", querySurfacePointer, &extensionStrings);
InsertExtensionString("EGL_ANGLE_window_fixed_size", windowFixedSize, &extensionStrings);
+ InsertExtensionString("EGL_ANGLE_keyed_mutex", keyedMutex, &extensionStrings);
+ InsertExtensionString("EGL_ANGLE_surface_orientation", surfaceOrientation, &extensionStrings);
+ InsertExtensionString("EGL_ANGLE_direct_composition", directComposition, &extensionStrings);
InsertExtensionString("EGL_NV_post_sub_buffer", postSubBuffer, &extensionStrings);
InsertExtensionString("EGL_KHR_create_context", createContext, &extensionStrings);
+ InsertExtensionString("EGL_EXT_device_query", deviceQuery, &extensionStrings);
+ InsertExtensionString("EGL_KHR_image", image, &extensionStrings);
+ InsertExtensionString("EGL_KHR_image_base", imageBase, &extensionStrings);
+ InsertExtensionString("EGL_KHR_image_pixmap", imagePixmap, &extensionStrings);
+ InsertExtensionString("EGL_KHR_gl_texture_2D_image", glTexture2DImage, &extensionStrings);
+ InsertExtensionString("EGL_KHR_gl_texture_cubemap_image", glTextureCubemapImage, &extensionStrings);
+ InsertExtensionString("EGL_KHR_gl_texture_3D_image", glTexture3DImage, &extensionStrings);
+ InsertExtensionString("EGL_KHR_gl_renderbuffer_image", glRenderbufferImage, &extensionStrings);
+ InsertExtensionString("EGL_KHR_get_all_proc_addresses", getAllProcAddresses, &extensionStrings);
+ InsertExtensionString("EGL_ANGLE_flexible_surface_compatibility", flexibleSurfaceCompatibility, &extensionStrings);
+ // TODO(jmadill): Enable this when complete.
+ //InsertExtensionString("KHR_create_context_no_error", createContextNoError, &extensionStrings);
+ // clang-format on
return extensionStrings;
}
+DeviceExtensions::DeviceExtensions()
+ : deviceD3D(false)
+{
+}
+
+std::vector<std::string> DeviceExtensions::getStrings() const
+{
+ std::vector<std::string> extensionStrings;
+
+ // | Extension name | Supported flag | Output vector |
+ InsertExtensionString("EGL_ANGLE_device_d3d", deviceD3D, &extensionStrings);
+
+ return extensionStrings;
+}
ClientExtensions::ClientExtensions()
: clientExtensions(false),
platformBase(false),
+ platformDevice(false),
platformANGLE(false),
platformANGLED3D(false),
- platformANGLEOpenGL(false)
+ platformANGLEOpenGL(false),
+ deviceCreation(false),
+ deviceCreationD3D11(false),
+ x11Visual(false),
+ experimentalPresentPath(false),
+ clientGetAllProcAddresses(false)
{
}
@@ -514,12 +706,20 @@ std::vector<std::string> ClientExtensions::getStrings() const
{
std::vector<std::string> extensionStrings;
- // | Extension name | Supported flag | Output vector |
- InsertExtensionString("EGL_EXT_client_extensions", clientExtensions, &extensionStrings);
- InsertExtensionString("EGL_EXT_platform_base", platformBase, &extensionStrings);
- InsertExtensionString("EGL_ANGLE_platform_angle", platformANGLE, &extensionStrings);
- InsertExtensionString("EGL_ANGLE_platform_angle_d3d", platformANGLED3D, &extensionStrings);
- InsertExtensionString("EGL_ANGLE_platform_angle_opengl", platformANGLEOpenGL, &extensionStrings);
+ // clang-format off
+ // | Extension name | Supported flag | Output vector |
+ InsertExtensionString("EGL_EXT_client_extensions", clientExtensions, &extensionStrings);
+ InsertExtensionString("EGL_EXT_platform_base", platformBase, &extensionStrings);
+ InsertExtensionString("EGL_EXT_platform_device", platformDevice, &extensionStrings);
+ InsertExtensionString("EGL_ANGLE_platform_angle", platformANGLE, &extensionStrings);
+ InsertExtensionString("EGL_ANGLE_platform_angle_d3d", platformANGLED3D, &extensionStrings);
+ InsertExtensionString("EGL_ANGLE_platform_angle_opengl", platformANGLEOpenGL, &extensionStrings);
+ InsertExtensionString("EGL_ANGLE_device_creation", deviceCreation, &extensionStrings);
+ InsertExtensionString("EGL_ANGLE_device_creation_d3d11", deviceCreationD3D11, &extensionStrings);
+ InsertExtensionString("EGL_ANGLE_x11_visual", x11Visual, &extensionStrings);
+ InsertExtensionString("EGL_ANGLE_experimental_present_path", experimentalPresentPath, &extensionStrings);
+ InsertExtensionString("EGL_KHR_client_get_all_proc_addresses", clientGetAllProcAddresses, &extensionStrings);
+ // clang-format on
return extensionStrings;
}
diff --git a/src/3rdparty/angle/src/libANGLE/Caps.h b/src/3rdparty/angle/src/libANGLE/Caps.h
index 37a634226a..d0e839a2ba 100644
--- a/src/3rdparty/angle/src/libANGLE/Caps.h
+++ b/src/3rdparty/angle/src/libANGLE/Caps.h
@@ -33,6 +33,7 @@ struct TextureCaps
// Support for being used as a framebuffer attachment or renderbuffer format
bool renderable;
+ // Set of supported sample counts, only guaranteed to be valid in ES3.
SupportedSampleSet sampleCounts;
// Get the maximum number of samples supported
@@ -72,14 +73,19 @@ struct Extensions
// Set all texture related extension support based on the supported textures.
// Determines support for:
+ // GL_OES_packed_depth_stencil
// GL_OES_rgb8_rgba8
// GL_EXT_texture_format_BGRA8888
+ // GL_EXT_color_buffer_half_float,
// GL_OES_texture_half_float, GL_OES_texture_half_float_linear
// GL_OES_texture_float, GL_OES_texture_float_linear
// GL_EXT_texture_rg
- // GL_EXT_texture_compression_dxt1, GL_ANGLE_texture_compression_dxt3, GL_ANGLE_texture_compression_dxt5
+ // GL_EXT_texture_compression_dxt1, GL_ANGLE_texture_compression_dxt3,
+ // GL_ANGLE_texture_compression_dxt5
+ // GL_KHR_texture_compression_astc_hdr, GL_KHR_texture_compression_astc_ldr
+ // GL_OES_compressed_ETC1_RGB8_texture
// GL_EXT_sRGB
- // GL_ANGLE_depth_texture
+ // GL_ANGLE_depth_texture, GL_OES_depth32
// GL_EXT_color_buffer_float
void setTextureExtensionSupport(const TextureCapsMap &textureCaps);
@@ -112,6 +118,11 @@ struct Extensions
bool mapBuffer;
bool mapBufferRange;
+ // GL_EXT_color_buffer_half_float
+ // Together with GL_OES_texture_half_float in a GLES 2.0 context, implies that half-float
+ // textures are renderable.
+ bool colorBufferHalfFloat;
+
// GL_OES_texture_half_float and GL_OES_texture_half_float_linear
// Implies that TextureCaps for GL_RGB16F, GL_RGBA16F, GL_ALPHA32F_EXT, GL_LUMINANCE32F_EXT and
// GL_LUMINANCE_ALPHA32F_EXT exist
@@ -136,6 +147,16 @@ struct Extensions
bool textureCompressionDXT3;
bool textureCompressionDXT5;
+ // GL_KHR_texture_compression_astc_hdr
+ bool textureCompressionASTCHDR;
+
+ // GL_KHR_texture_compression_astc_ldr
+ bool textureCompressionASTCLDR;
+
+ // GL_OES_compressed_ETC1_RGB8_texture
+ // Implies that TextureCaps for GL_ETC1_RGB8_OES exist
+ bool compressedETC1RGB8Texture;
+
// GL_EXT_sRGB
// Implies that TextureCaps for GL_SRGB8_ALPHA8 and GL_SRGB8 exist
// TODO: Don't advertise this extension in ES3
@@ -144,6 +165,10 @@ struct Extensions
// GL_ANGLE_depth_texture
bool depthTextures;
+ // GL_OES_depth32
+ // Allows DEPTH_COMPONENT32_OES as a valid Renderbuffer format.
+ bool depth32;
+
// GL_EXT_texture_storage
bool textureStorage;
@@ -166,6 +191,11 @@ struct Extensions
// GL_ANGLE_timer_query
bool timerQuery;
+ // GL_EXT_disjoint_timer_query
+ bool disjointTimerQuery;
+ GLuint queryCounterBitsTimeElapsed;
+ GLuint queryCounterBitsTimestamp;
+
// GL_EXT_robustness
bool robustness;
@@ -177,7 +207,6 @@ struct Extensions
// GL_ANGLE_framebuffer_multisample
bool framebufferMultisample;
- GLuint maxSamples;
// GL_ANGLE_instanced_arrays
bool instancedArrays;
@@ -209,12 +238,76 @@ struct Extensions
// GL_ANGLE_translated_shader_source
bool translatedShaderSource;
+ // GL_OES_fbo_render_mipmap
+ bool fboRenderMipmap;
+
+ // GL_EXT_discard_framebuffer
+ bool discardFramebuffer;
+
+ // EXT_debug_marker
+ bool debugMarker;
+
+ // GL_OES_EGL_image
+ bool eglImage;
+
+ // GL_OES_EGL_image_external
+ bool eglImageExternal;
+
+ // GL_OES_EGL_image_external_essl3
+ bool eglImageExternalEssl3;
+
+ // EXT_unpack_subimage
+ bool unpackSubimage;
+
+ // NV_pack_subimage
+ bool packSubimage;
+
+ // GL_OES_vertex_array_object
+ bool vertexArrayObject;
+
+ // GL_KHR_debug
+ bool debug;
+ GLuint maxDebugMessageLength;
+ GLuint maxDebugLoggedMessages;
+ GLuint maxDebugGroupStackDepth;
+ GLuint maxLabelLength;
+
+ // KHR_no_error
+ bool noError;
+
+ // GL_ANGLE_lossy_etc_decode
+ bool lossyETCDecode;
+
// ES3 Extension support
// GL_EXT_color_buffer_float
bool colorBufferFloat;
};
+struct Limitations
+{
+ Limitations();
+
+ // Renderer doesn't support gl_FrontFacing in fragment shaders
+ bool noFrontFacingSupport;
+
+ // Renderer doesn't support GL_SAMPLE_ALPHA_TO_COVERAGE
+ bool noSampleAlphaToCoverageSupport;
+
+ // In glVertexAttribDivisorANGLE, attribute zero must have a zero divisor
+ bool attributeZeroRequiresZeroDivisorInEXT;
+
+ // Unable to support different values for front and back faces for stencil refs and masks
+ bool noSeparateStencilRefsAndMasks;
+
+ // Renderer doesn't support non-constant indexing loops in fragment shader
+ bool shadersRequireIndexedLoopValidation;
+
+ // Renderer doesn't support Simultaneous use of GL_CONSTANT_ALPHA/GL_ONE_MINUS_CONSTANT_ALPHA
+ // and GL_CONSTANT_COLOR/GL_ONE_MINUS_CONSTANT_COLOR blend functions.
+ bool noSimultaneousConstantColorAndAlphaBlendFunc;
+};
+
struct TypePrecision
{
TypePrecision();
@@ -302,6 +395,9 @@ struct Caps
GLuint maxTransformFeedbackInterleavedComponents;
GLuint maxTransformFeedbackSeparateAttributes;
GLuint maxTransformFeedbackSeparateComponents;
+
+ // Table 6.35, Framebuffer Dependent Values
+ GLuint maxSamples;
};
}
@@ -339,11 +435,64 @@ struct DisplayExtensions
// EGL_ANGLE_window_fixed_size
bool windowFixedSize;
+ // EGL_ANGLE_keyed_mutex
+ bool keyedMutex;
+
+ // EGL_ANGLE_surface_orientation
+ bool surfaceOrientation;
+
// EGL_NV_post_sub_buffer
bool postSubBuffer;
// EGL_KHR_create_context
bool createContext;
+
+ // EGL_EXT_device_query
+ bool deviceQuery;
+
+ // EGL_KHR_image
+ bool image;
+
+ // EGL_KHR_image_base
+ bool imageBase;
+
+ // EGL_KHR_image_pixmap
+ bool imagePixmap;
+
+ // EGL_KHR_gl_texture_2D_image
+ bool glTexture2DImage;
+
+ // EGL_KHR_gl_texture_cubemap_image
+ bool glTextureCubemapImage;
+
+ // EGL_KHR_gl_texture_3D_image
+ bool glTexture3DImage;
+
+ // EGL_KHR_gl_renderbuffer_image
+ bool glRenderbufferImage;
+
+ // EGL_KHR_get_all_proc_addresses
+ bool getAllProcAddresses;
+
+ // EGL_ANGLE_flexible_surface_compatibility
+ bool flexibleSurfaceCompatibility;
+
+ // EGL_ANGLE_direct_composition
+ bool directComposition;
+
+ // KHR_create_context_no_error
+ bool createContextNoError;
+};
+
+struct DeviceExtensions
+{
+ DeviceExtensions();
+
+ // Generate a vector of supported extension strings
+ std::vector<std::string> getStrings() const;
+
+ // EGL_ANGLE_device_d3d
+ bool deviceD3D;
};
struct ClientExtensions
@@ -359,6 +508,9 @@ struct ClientExtensions
// EGL_EXT_platform_base
bool platformBase;
+ // EGL_EXT_platform_device
+ bool platformDevice;
+
// EGL_ANGLE_platform_angle
bool platformANGLE;
@@ -367,6 +519,21 @@ struct ClientExtensions
// EGL_ANGLE_platform_angle_opengl
bool platformANGLEOpenGL;
+
+ // EGL_ANGLE_device_creation
+ bool deviceCreation;
+
+ // EGL_ANGLE_device_creation_d3d11
+ bool deviceCreationD3D11;
+
+ // EGL_ANGLE_x11_visual
+ bool x11Visual;
+
+ // EGL_ANGLE_experimental_present_path
+ bool experimentalPresentPath;
+
+ // EGL_KHR_client_get_all_proc_addresses
+ bool clientGetAllProcAddresses;
};
}
diff --git a/src/3rdparty/angle/src/libANGLE/Compiler.cpp b/src/3rdparty/angle/src/libANGLE/Compiler.cpp
index 7d0efea220..348c41bef3 100644
--- a/src/3rdparty/angle/src/libANGLE/Compiler.cpp
+++ b/src/3rdparty/angle/src/libANGLE/Compiler.cpp
@@ -7,32 +7,128 @@
// Compiler.cpp: implements the gl::Compiler class.
#include "libANGLE/Compiler.h"
-#include "libANGLE/renderer/CompilerImpl.h"
#include "common/debug.h"
+#include "libANGLE/Data.h"
+#include "libANGLE/renderer/CompilerImpl.h"
+#include "libANGLE/renderer/ImplFactory.h"
namespace gl
{
-Compiler::Compiler(rx::CompilerImpl *impl)
- : mCompiler(impl)
+namespace
+{
+
+// Global count of active shader compiler handles. Needed to know when to call ShInitialize and
+// ShFinalize.
+size_t activeCompilerHandles = 0;
+
+} // anonymous namespace
+
+Compiler::Compiler(rx::ImplFactory *implFactory, const gl::Data &data)
+ : mImplementation(implFactory->createCompiler()),
+ mSpec(data.clientVersion > 2 ? SH_GLES3_SPEC : SH_GLES2_SPEC),
+ mOutputType(mImplementation->getTranslatorOutputType()),
+ mResources(),
+ mFragmentCompiler(nullptr),
+ mVertexCompiler(nullptr)
{
- ASSERT(mCompiler);
+ ASSERT(data.clientVersion == 2 || data.clientVersion == 3);
+
+ const gl::Caps &caps = *data.caps;
+ const gl::Extensions &extensions = *data.extensions;
+
+ ShInitBuiltInResources(&mResources);
+ mResources.MaxVertexAttribs = caps.maxVertexAttributes;
+ mResources.MaxVertexUniformVectors = caps.maxVertexUniformVectors;
+ mResources.MaxVaryingVectors = caps.maxVaryingVectors;
+ mResources.MaxVertexTextureImageUnits = caps.maxVertexTextureImageUnits;
+ mResources.MaxCombinedTextureImageUnits = caps.maxCombinedTextureImageUnits;
+ mResources.MaxTextureImageUnits = caps.maxTextureImageUnits;
+ mResources.MaxFragmentUniformVectors = caps.maxFragmentUniformVectors;
+ mResources.MaxDrawBuffers = caps.maxDrawBuffers;
+ mResources.OES_standard_derivatives = extensions.standardDerivatives;
+ mResources.EXT_draw_buffers = extensions.drawBuffers;
+ mResources.EXT_shader_texture_lod = extensions.shaderTextureLOD;
+ // TODO: disabled until the extension is actually supported.
+ mResources.OES_EGL_image_external = 0;
+ // TODO: use shader precision caps to determine if high precision is supported?
+ mResources.FragmentPrecisionHigh = 1;
+ mResources.EXT_frag_depth = extensions.fragDepth;
+
+ // GLSL ES 3.0 constants
+ mResources.MaxVertexOutputVectors = caps.maxVertexOutputComponents / 4;
+ mResources.MaxFragmentInputVectors = caps.maxFragmentInputComponents / 4;
+ mResources.MinProgramTexelOffset = caps.minProgramTexelOffset;
+ mResources.MaxProgramTexelOffset = caps.maxProgramTexelOffset;
}
Compiler::~Compiler()
{
- SafeDelete(mCompiler);
+ release();
+ SafeDelete(mImplementation);
}
Error Compiler::release()
{
- return mCompiler->release();
+ if (mFragmentCompiler)
+ {
+ ShDestruct(mFragmentCompiler);
+ mFragmentCompiler = nullptr;
+
+ ASSERT(activeCompilerHandles > 0);
+ activeCompilerHandles--;
+ }
+
+ if (mVertexCompiler)
+ {
+ ShDestruct(mVertexCompiler);
+ mVertexCompiler = nullptr;
+
+ ASSERT(activeCompilerHandles > 0);
+ activeCompilerHandles--;
+ }
+
+ if (activeCompilerHandles == 0)
+ {
+ ShFinalize();
+ }
+
+ mImplementation->release();
+
+ return gl::Error(GL_NO_ERROR);
}
-rx::CompilerImpl *Compiler::getImplementation()
+ShHandle Compiler::getCompilerHandle(GLenum type)
{
- return mCompiler;
-}
+ ShHandle *compiler = nullptr;
+ switch (type)
+ {
+ case GL_VERTEX_SHADER:
+ compiler = &mVertexCompiler;
+ break;
+ case GL_FRAGMENT_SHADER:
+ compiler = &mFragmentCompiler;
+ break;
+
+ default:
+ UNREACHABLE();
+ return nullptr;
+ }
+
+ if (!(*compiler))
+ {
+ if (activeCompilerHandles == 0)
+ {
+ ShInitialize();
+ }
+
+ *compiler = ShConstructCompiler(type, mSpec, mOutputType, &mResources);
+ activeCompilerHandles++;
+ }
+
+ return *compiler;
}
+
+} // namespace gl
diff --git a/src/3rdparty/angle/src/libANGLE/Compiler.h b/src/3rdparty/angle/src/libANGLE/Compiler.h
index 05de15ec97..8634e39a45 100644
--- a/src/3rdparty/angle/src/libANGLE/Compiler.h
+++ b/src/3rdparty/angle/src/libANGLE/Compiler.h
@@ -11,29 +11,39 @@
#define LIBANGLE_COMPILER_H_
#include "libANGLE/Error.h"
+#include "GLSLANG/ShaderLang.h"
namespace rx
{
class CompilerImpl;
+class ImplFactory;
}
namespace gl
{
+struct Data;
-class Compiler final
+class Compiler final : angle::NonCopyable
{
public:
- explicit Compiler(rx::CompilerImpl *impl);
+ Compiler(rx::ImplFactory *implFactory, const Data &data);
~Compiler();
Error release();
- rx::CompilerImpl *getImplementation();
+ ShHandle getCompilerHandle(GLenum type);
+ ShShaderOutput getShaderOutputType() const { return mOutputType; }
private:
- rx::CompilerImpl *mCompiler;
+ rx::CompilerImpl *mImplementation;
+ ShShaderSpec mSpec;
+ ShShaderOutput mOutputType;
+ ShBuiltInResources mResources;
+
+ ShHandle mFragmentCompiler;
+ ShHandle mVertexCompiler;
};
-}
+} // namespace gl
#endif // LIBANGLE_COMPILER_H_
diff --git a/src/3rdparty/angle/src/libANGLE/Config.cpp b/src/3rdparty/angle/src/libANGLE/Config.cpp
index 1b1fc50cb3..d511df3a69 100644
--- a/src/3rdparty/angle/src/libANGLE/Config.cpp
+++ b/src/3rdparty/angle/src/libANGLE/Config.cpp
@@ -57,14 +57,15 @@ Config::Config()
transparentType(EGL_NONE),
transparentRedValue(0),
transparentGreenValue(0),
- transparentBlueValue(0)
+ transparentBlueValue(0),
+ optimalOrientation(0)
{
}
EGLint ConfigSet::add(const Config &config)
{
// Set the config's ID to a small number that starts at 1 ([EGL 1.5] section 3.4)
- EGLint id = mConfigs.size() + 1;
+ EGLint id = static_cast<EGLint>(mConfigs.size()) + 1;
Config copyConfig(config);
copyConfig.configID = id;
@@ -251,6 +252,9 @@ std::vector<const Config*> ConfigSet::filter(const AttributeMap &attributeMap) c
case EGL_MAX_PBUFFER_WIDTH: match = config.maxPBufferWidth >= attributeValue; break;
case EGL_MAX_PBUFFER_HEIGHT: match = config.maxPBufferHeight >= attributeValue; break;
case EGL_MAX_PBUFFER_PIXELS: match = config.maxPBufferPixels >= attributeValue; break;
+ case EGL_OPTIMAL_SURFACE_ORIENTATION_ANGLE:
+ match = config.optimalOrientation == attributeValue;
+ break;
default: UNREACHABLE();
}
diff --git a/src/3rdparty/angle/src/libANGLE/Config.h b/src/3rdparty/angle/src/libANGLE/Config.h
index aed8aedb1d..00f5673b59 100644
--- a/src/3rdparty/angle/src/libANGLE/Config.h
+++ b/src/3rdparty/angle/src/libANGLE/Config.h
@@ -64,6 +64,7 @@ struct Config
EGLint transparentRedValue; // Transparent red value
EGLint transparentGreenValue; // Transparent green value
EGLint transparentBlueValue; // Transparent blue value
+ EGLint optimalOrientation; // Optimal window surface orientation
};
class ConfigSet
diff --git a/src/3rdparty/angle/src/libANGLE/Context.cpp b/src/3rdparty/angle/src/libANGLE/Context.cpp
index 1da5fdae95..26f2970068 100644
--- a/src/3rdparty/angle/src/libANGLE/Context.cpp
+++ b/src/3rdparty/angle/src/libANGLE/Context.cpp
@@ -33,22 +33,124 @@
#include "libANGLE/validationES.h"
#include "libANGLE/renderer/Renderer.h"
-namespace gl
+namespace
+{
+
+template <typename T>
+gl::Error GetQueryObjectParameter(gl::Context *context, GLuint id, GLenum pname, T *params)
+{
+ gl::Query *queryObject = context->getQuery(id, false, GL_NONE);
+ ASSERT(queryObject != nullptr);
+
+ switch (pname)
+ {
+ case GL_QUERY_RESULT_EXT:
+ return queryObject->getResult(params);
+ case GL_QUERY_RESULT_AVAILABLE_EXT:
+ {
+ bool available;
+ gl::Error error = queryObject->isResultAvailable(&available);
+ if (!error.isError())
+ {
+ *params = static_cast<T>(available ? GL_TRUE : GL_FALSE);
+ }
+ return error;
+ }
+ default:
+ UNREACHABLE();
+ return gl::Error(GL_INVALID_OPERATION, "Unreachable Error");
+ }
+}
+
+void MarkTransformFeedbackBufferUsage(gl::TransformFeedback *transformFeedback)
+{
+ if (transformFeedback && transformFeedback->isActive() && !transformFeedback->isPaused())
+ {
+ for (size_t tfBufferIndex = 0; tfBufferIndex < transformFeedback->getIndexedBufferCount();
+ tfBufferIndex++)
+ {
+ const OffsetBindingPointer<gl::Buffer> &buffer =
+ transformFeedback->getIndexedBuffer(tfBufferIndex);
+ if (buffer.get() != nullptr)
+ {
+ buffer->onTransformFeedback();
+ }
+ }
+ }
+}
+
+// Attribute map queries.
+EGLint GetClientVersion(const egl::AttributeMap &attribs)
+{
+ return attribs.get(EGL_CONTEXT_CLIENT_VERSION, 1);
+}
+
+GLenum GetResetStrategy(const egl::AttributeMap &attribs)
+{
+ EGLenum attrib = attribs.get(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT,
+ EGL_NO_RESET_NOTIFICATION_EXT);
+ switch (attrib)
+ {
+ case EGL_NO_RESET_NOTIFICATION:
+ return GL_NO_RESET_NOTIFICATION_EXT;
+ case EGL_LOSE_CONTEXT_ON_RESET:
+ return GL_LOSE_CONTEXT_ON_RESET_EXT;
+ default:
+ UNREACHABLE();
+ return GL_NONE;
+ }
+}
+
+bool GetRobustAccess(const egl::AttributeMap &attribs)
+{
+ return (attribs.get(EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT, EGL_FALSE) == EGL_TRUE);
+}
+
+bool GetDebug(const egl::AttributeMap &attribs)
{
+ return (attribs.get(EGL_CONTEXT_OPENGL_DEBUG, EGL_FALSE) == EGL_TRUE);
+}
-Context::Context(const egl::Config *config, int clientVersion, const Context *shareContext, rx::Renderer *renderer, bool notifyResets, bool robustAccess)
- : mRenderer(renderer)
+bool GetNoError(const egl::AttributeMap &attribs)
{
- ASSERT(robustAccess == false); // Unimplemented
+ return (attribs.get(EGL_CONTEXT_OPENGL_NO_ERROR_KHR, EGL_FALSE) == EGL_TRUE);
+}
- initCaps(clientVersion);
- mState.initialize(mCaps, clientVersion);
+} // anonymous namespace
- mClientVersion = clientVersion;
+namespace gl
+{
- mConfigID = config->configID;
- mClientType = EGL_OPENGL_ES_API;
- mRenderBuffer = EGL_NONE;
+Context::Context(const egl::Config *config,
+ const Context *shareContext,
+ rx::Renderer *renderer,
+ const egl::AttributeMap &attribs)
+ : ValidationContext(GetClientVersion(attribs),
+ mState,
+ mCaps,
+ mTextureCaps,
+ mExtensions,
+ nullptr,
+ mLimitations,
+ GetNoError(attribs)),
+ mCompiler(nullptr),
+ mRenderer(renderer),
+ mClientVersion(GetClientVersion(attribs)),
+ mConfig(config),
+ mClientType(EGL_OPENGL_ES_API),
+ mHasBeenCurrent(false),
+ mContextLost(false),
+ mResetStatus(GL_NO_ERROR),
+ mResetStrategy(GetResetStrategy(attribs)),
+ mRobustAccess(GetRobustAccess(attribs)),
+ mCurrentSurface(nullptr),
+ mResourceManager(nullptr)
+{
+ ASSERT(!mRobustAccess); // Unimplemented
+
+ initCaps(mClientVersion);
+
+ mState.initialize(mCaps, mExtensions, mClientVersion, GetDebug(attribs));
mFenceNVHandleAllocator.setBaseHandle(0);
@@ -62,6 +164,8 @@ Context::Context(const egl::Config *config, int clientVersion, const Context *sh
mResourceManager = new ResourceManager(mRenderer);
}
+ mData.resourceManager = mResourceManager;
+
// [OpenGL ES 2.0.24] section 3.7 page 83:
// In the initial state, TEXTURE_2D and TEXTURE_CUBE_MAP have twodimensional
// and cube map texture state vectors respectively associated with them.
@@ -90,8 +194,6 @@ Context::Context(const egl::Config *config, int clientVersion, const Context *sh
bindArrayBuffer(0);
bindElementArrayBuffer(0);
- bindReadFramebuffer(0);
- bindDrawFramebuffer(0);
bindRenderbuffer(0);
bindGenericUniformBuffer(0);
@@ -100,70 +202,73 @@ Context::Context(const egl::Config *config, int clientVersion, const Context *sh
bindIndexedUniformBuffer(0, i, 0, -1);
}
- bindGenericTransformFeedbackBuffer(0);
- for (unsigned int i = 0; i < mCaps.maxTransformFeedbackSeparateAttributes; i++)
- {
- bindIndexedTransformFeedbackBuffer(0, i, 0, -1);
- }
-
bindCopyReadBuffer(0);
bindCopyWriteBuffer(0);
bindPixelPackBuffer(0);
bindPixelUnpackBuffer(0);
- // [OpenGL ES 3.0.2] section 2.14.1 pg 85:
- // In the initial state, a default transform feedback object is bound and treated as
- // a transform feedback object with a name of zero. That object is bound any time
- // BindTransformFeedback is called with id of zero
- mTransformFeedbackZero.set(new TransformFeedback(mRenderer->createTransformFeedback(), 0));
- bindTransformFeedback(0);
-
- mHasBeenCurrent = false;
- mContextLost = false;
- mResetStatus = GL_NO_ERROR;
- mResetStrategy = (notifyResets ? GL_LOSE_CONTEXT_ON_RESET_EXT : GL_NO_RESET_NOTIFICATION_EXT);
- mRobustAccess = robustAccess;
+ if (mClientVersion >= 3)
+ {
+ // [OpenGL ES 3.0.2] section 2.14.1 pg 85:
+ // In the initial state, a default transform feedback object is bound and treated as
+ // a transform feedback object with a name of zero. That object is bound any time
+ // BindTransformFeedback is called with id of zero
+ bindTransformFeedback(0);
+ }
- mCompiler = new Compiler(mRenderer->createCompiler(getData()));
+ mCompiler = new Compiler(mRenderer, getData());
}
Context::~Context()
{
mState.reset();
- while (!mFramebufferMap.empty())
+ for (auto framebuffer : mFramebufferMap)
{
- // Delete the framebuffer in reverse order to destroy the framebuffer zero last.
- deleteFramebuffer(mFramebufferMap.rbegin()->first);
+ // Default framebuffer are owned by their respective Surface
+ if (framebuffer.second != nullptr && framebuffer.second->id() != 0)
+ {
+ SafeDelete(framebuffer.second);
+ }
}
- while (!mFenceNVMap.empty())
+ for (auto fence : mFenceNVMap)
{
- deleteFenceNV(mFenceNVMap.begin()->first);
+ SafeDelete(fence.second);
}
- while (!mQueryMap.empty())
+ for (auto query : mQueryMap)
{
- deleteQuery(mQueryMap.begin()->first);
+ if (query.second != nullptr)
+ {
+ query.second->release();
+ }
}
- while (!mVertexArrayMap.empty())
+ for (auto vertexArray : mVertexArrayMap)
{
- deleteVertexArray(mVertexArrayMap.begin()->first);
+ SafeDelete(vertexArray.second);
}
- mTransformFeedbackZero.set(NULL);
- while (!mTransformFeedbackMap.empty())
+ for (auto transformFeedback : mTransformFeedbackMap)
{
- deleteTransformFeedback(mTransformFeedbackMap.begin()->first);
+ if (transformFeedback.second != nullptr)
+ {
+ transformFeedback.second->release();
+ }
}
- for (auto it = mZeroTextures.begin(); it != mZeroTextures.end(); ++it)
+ for (auto &zeroTexture : mZeroTextures)
{
- it->second.set(NULL);
+ zeroTexture.second.set(NULL);
}
mZeroTextures.clear();
+ if (mCurrentSurface != nullptr)
+ {
+ releaseSurface();
+ }
+
if (mResourceManager)
{
mResourceManager->release();
@@ -174,6 +279,8 @@ Context::~Context()
void Context::makeCurrent(egl::Surface *surface)
{
+ ASSERT(surface != nullptr);
+
if (!mHasBeenCurrent)
{
initRendererString();
@@ -185,12 +292,55 @@ void Context::makeCurrent(egl::Surface *surface)
mHasBeenCurrent = true;
}
- // TODO(jmadill): do not allocate new pointers here
- Framebuffer *framebufferZero = new DefaultFramebuffer(mCaps, mRenderer, surface);
+ // TODO(jmadill): Rework this when we support ContextImpl
+ mState.setAllDirtyBits();
- setFramebufferZero(framebufferZero);
+ if (mCurrentSurface)
+ {
+ releaseSurface();
+ }
+ surface->setIsCurrent(true);
+ mCurrentSurface = surface;
+
+ // Update default framebuffer, the binding of the previous default
+ // framebuffer (or lack of) will have a nullptr.
+ {
+ Framebuffer *newDefault = surface->getDefaultFramebuffer();
+ if (mState.getReadFramebuffer() == nullptr)
+ {
+ mState.setReadFramebufferBinding(newDefault);
+ }
+ if (mState.getDrawFramebuffer() == nullptr)
+ {
+ mState.setDrawFramebufferBinding(newDefault);
+ }
+ mFramebufferMap[0] = newDefault;
+ }
- mRenderBuffer = surface->getRenderBuffer();
+ // Notify the renderer of a context switch
+ mRenderer->onMakeCurrent(getData());
+}
+
+void Context::releaseSurface()
+{
+ ASSERT(mCurrentSurface != nullptr);
+
+ // Remove the default framebuffer
+ {
+ Framebuffer *currentDefault = mCurrentSurface->getDefaultFramebuffer();
+ if (mState.getReadFramebuffer() == currentDefault)
+ {
+ mState.setReadFramebufferBinding(nullptr);
+ }
+ if (mState.getDrawFramebuffer() == currentDefault)
+ {
+ mState.setDrawFramebufferBinding(nullptr);
+ }
+ mFramebufferMap.erase(0);
+ }
+
+ mCurrentSurface->setIsCurrent(false);
+ mCurrentSurface = nullptr;
}
// NOTE: this function should not assume that this context is current!
@@ -218,7 +368,7 @@ GLuint Context::createProgram()
GLuint Context::createShader(GLenum type)
{
- return mResourceManager->createShader(getData(), type);
+ return mResourceManager->createShader(mRenderer->getRendererLimitations(), type);
}
GLuint Context::createTexture()
@@ -240,14 +390,9 @@ GLsync Context::createFenceSync()
GLuint Context::createVertexArray()
{
- GLuint handle = mVertexArrayHandleAllocator.allocate();
-
- // Although the spec states VAO state is not initialized until the object is bound,
- // we create it immediately. The resulting behaviour is transparent to the application,
- // since it's not currently possible to access the state until the object is bound.
- VertexArray *vertexArray = new VertexArray(mRenderer->createVertexArray(), handle, MAX_VERTEX_ATTRIBS);
- mVertexArrayMap[handle] = vertexArray;
- return handle;
+ GLuint vertexArray = mVertexArrayHandleAllocator.allocate();
+ mVertexArrayMap[vertexArray] = nullptr;
+ return vertexArray;
}
GLuint Context::createSampler()
@@ -257,11 +402,9 @@ GLuint Context::createSampler()
GLuint Context::createTransformFeedback()
{
- GLuint handle = mTransformFeedbackAllocator.allocate();
- TransformFeedback *transformFeedback = new TransformFeedback(mRenderer->createTransformFeedback(), handle);
- transformFeedback->addRef();
- mTransformFeedbackMap[handle] = transformFeedback;
- return handle;
+ GLuint transformFeedback = mTransformFeedbackAllocator.allocate();
+ mTransformFeedbackMap[transformFeedback] = nullptr;
+ return transformFeedback;
}
// Returns an unused framebuffer name
@@ -339,20 +482,23 @@ void Context::deleteFenceSync(GLsync fenceSync)
// wait commands finish. However, since the name becomes invalid, we cannot query the fence,
// and since our API is currently designed for being called from a single thread, we can delete
// the fence immediately.
- mResourceManager->deleteFenceSync(reinterpret_cast<uintptr_t>(fenceSync));
+ mResourceManager->deleteFenceSync(static_cast<GLuint>(reinterpret_cast<uintptr_t>(fenceSync)));
}
void Context::deleteVertexArray(GLuint vertexArray)
{
- auto vertexArrayObject = mVertexArrayMap.find(vertexArray);
-
- if (vertexArrayObject != mVertexArrayMap.end())
+ auto iter = mVertexArrayMap.find(vertexArray);
+ if (iter != mVertexArrayMap.end())
{
- detachVertexArray(vertexArray);
+ VertexArray *vertexArrayObject = iter->second;
+ if (vertexArrayObject != nullptr)
+ {
+ detachVertexArray(vertexArray);
+ delete vertexArrayObject;
+ }
- mVertexArrayHandleAllocator.release(vertexArrayObject->first);
- delete vertexArrayObject->second;
- mVertexArrayMap.erase(vertexArrayObject);
+ mVertexArrayMap.erase(iter);
+ mVertexArrayHandleAllocator.release(vertexArray);
}
}
@@ -371,10 +517,15 @@ void Context::deleteTransformFeedback(GLuint transformFeedback)
auto iter = mTransformFeedbackMap.find(transformFeedback);
if (iter != mTransformFeedbackMap.end())
{
- detachTransformFeedback(transformFeedback);
- mTransformFeedbackAllocator.release(transformFeedback);
- iter->second->release();
+ TransformFeedback *transformFeedbackObject = iter->second;
+ if (transformFeedbackObject != nullptr)
+ {
+ detachTransformFeedback(transformFeedback);
+ transformFeedbackObject->release();
+ }
+
mTransformFeedbackMap.erase(iter);
+ mTransformFeedbackAllocator.release(transformFeedback);
}
}
@@ -418,7 +569,7 @@ void Context::deleteQuery(GLuint query)
}
}
-Buffer *Context::getBuffer(GLuint handle)
+Buffer *Context::getBuffer(GLuint handle) const
{
return mResourceManager->getBuffer(handle);
}
@@ -438,28 +589,20 @@ Texture *Context::getTexture(GLuint handle) const
return mResourceManager->getTexture(handle);
}
-Renderbuffer *Context::getRenderbuffer(GLuint handle)
+Renderbuffer *Context::getRenderbuffer(GLuint handle) const
{
return mResourceManager->getRenderbuffer(handle);
}
FenceSync *Context::getFenceSync(GLsync handle) const
{
- return mResourceManager->getFenceSync(reinterpret_cast<uintptr_t>(handle));
+ return mResourceManager->getFenceSync(static_cast<GLuint>(reinterpret_cast<uintptr_t>(handle)));
}
VertexArray *Context::getVertexArray(GLuint handle) const
{
auto vertexArray = mVertexArrayMap.find(handle);
-
- if (vertexArray == mVertexArrayMap.end())
- {
- return NULL;
- }
- else
- {
- return vertexArray->second;
- }
+ return (vertexArray != mVertexArrayMap.end()) ? vertexArray->second : nullptr;
}
Sampler *Context::getSampler(GLuint handle) const
@@ -469,17 +612,45 @@ Sampler *Context::getSampler(GLuint handle) const
TransformFeedback *Context::getTransformFeedback(GLuint handle) const
{
- if (handle == 0)
- {
- return mTransformFeedbackZero.get();
- }
- else
+ auto iter = mTransformFeedbackMap.find(handle);
+ return (iter != mTransformFeedbackMap.end()) ? iter->second : nullptr;
+}
+
+LabeledObject *Context::getLabeledObject(GLenum identifier, GLuint name) const
+{
+ switch (identifier)
{
- TransformFeedbackMap::const_iterator iter = mTransformFeedbackMap.find(handle);
- return (iter != mTransformFeedbackMap.end()) ? iter->second : NULL;
+ case GL_BUFFER:
+ return getBuffer(name);
+ case GL_SHADER:
+ return getShader(name);
+ case GL_PROGRAM:
+ return getProgram(name);
+ case GL_VERTEX_ARRAY:
+ return getVertexArray(name);
+ case GL_QUERY:
+ return getQuery(name);
+ case GL_TRANSFORM_FEEDBACK:
+ return getTransformFeedback(name);
+ case GL_SAMPLER:
+ return getSampler(name);
+ case GL_TEXTURE:
+ return getTexture(name);
+ case GL_RENDERBUFFER:
+ return getRenderbuffer(name);
+ case GL_FRAMEBUFFER:
+ return getFramebuffer(name);
+ default:
+ UNREACHABLE();
+ return nullptr;
}
}
+LabeledObject *Context::getLabeledObjectFromPtr(const void *ptr) const
+{
+ return getFenceSync(reinterpret_cast<GLsync>(const_cast<void *>(ptr)));
+}
+
bool Context::isSampler(GLuint samplerName) const
{
return mResourceManager->isSampler(samplerName);
@@ -518,24 +689,16 @@ void Context::bindTexture(GLenum target, GLuint handle)
mState.setSamplerTexture(target, texture);
}
-void Context::bindReadFramebuffer(GLuint framebuffer)
+void Context::bindReadFramebuffer(GLuint framebufferHandle)
{
- if (!getFramebuffer(framebuffer))
- {
- mFramebufferMap[framebuffer] = new Framebuffer(mCaps, mRenderer, framebuffer);
- }
-
- mState.setReadFramebufferBinding(getFramebuffer(framebuffer));
+ Framebuffer *framebuffer = checkFramebufferAllocation(framebufferHandle);
+ mState.setReadFramebufferBinding(framebuffer);
}
-void Context::bindDrawFramebuffer(GLuint framebuffer)
+void Context::bindDrawFramebuffer(GLuint framebufferHandle)
{
- if (!getFramebuffer(framebuffer))
- {
- mFramebufferMap[framebuffer] = new Framebuffer(mCaps, mRenderer, framebuffer);
- }
-
- mState.setDrawFramebufferBinding(getFramebuffer(framebuffer));
+ Framebuffer *framebuffer = checkFramebufferAllocation(framebufferHandle);
+ mState.setDrawFramebufferBinding(framebuffer);
}
void Context::bindRenderbuffer(GLuint renderbuffer)
@@ -547,11 +710,7 @@ void Context::bindRenderbuffer(GLuint renderbuffer)
void Context::bindVertexArray(GLuint vertexArray)
{
- if (!getVertexArray(vertexArray))
- {
- VertexArray *vertexArrayObject = new VertexArray(mRenderer->createVertexArray(), vertexArray, MAX_VERTEX_ATTRIBS);
- mVertexArrayMap[vertexArray] = vertexArrayObject;
- }
+ checkVertexArrayAllocation(vertexArray);
mState.setVertexArrayBinding(getVertexArray(vertexArray));
}
@@ -582,14 +741,14 @@ void Context::bindGenericTransformFeedbackBuffer(GLuint buffer)
{
mResourceManager->checkBufferAllocation(buffer);
- mState.setGenericTransformFeedbackBufferBinding(getBuffer(buffer));
+ mState.getCurrentTransformFeedback()->bindGenericBuffer(getBuffer(buffer));
}
void Context::bindIndexedTransformFeedbackBuffer(GLuint buffer, GLuint index, GLintptr offset, GLsizeiptr size)
{
mResourceManager->checkBufferAllocation(buffer);
- mState.setIndexedTransformFeedbackBufferBinding(index, getBuffer(buffer), offset, size);
+ mState.getCurrentTransformFeedback()->bindIndexedBuffer(index, getBuffer(buffer), offset, size);
}
void Context::bindCopyReadBuffer(GLuint buffer)
@@ -627,6 +786,8 @@ void Context::useProgram(GLuint program)
void Context::bindTransformFeedback(GLuint transformFeedback)
{
+ checkTransformFeedbackAllocation(transformFeedback);
+
mState.setTransformFeedbackBinding(getTransformFeedback(transformFeedback));
}
@@ -661,37 +822,68 @@ Error Context::endQuery(GLenum target)
return error;
}
-void Context::setFramebufferZero(Framebuffer *buffer)
+Error Context::queryCounter(GLuint id, GLenum target)
{
- // First, check to see if the old default framebuffer
- // was set for draw or read framebuffer, and change
- // the bindings to point to the new one before deleting it.
- if (mState.getDrawFramebuffer()->id() == 0)
- {
- mState.setDrawFramebufferBinding(buffer);
- }
+ ASSERT(target == GL_TIMESTAMP_EXT);
+
+ Query *queryObject = getQuery(id, true, target);
+ ASSERT(queryObject);
+
+ return queryObject->queryCounter();
+}
- if (mState.getReadFramebuffer()->id() == 0)
+void Context::getQueryiv(GLenum target, GLenum pname, GLint *params)
+{
+ switch (pname)
{
- mState.setReadFramebufferBinding(buffer);
+ case GL_CURRENT_QUERY_EXT:
+ params[0] = getState().getActiveQueryId(target);
+ break;
+ case GL_QUERY_COUNTER_BITS_EXT:
+ switch (target)
+ {
+ case GL_TIME_ELAPSED_EXT:
+ params[0] = getExtensions().queryCounterBitsTimeElapsed;
+ break;
+ case GL_TIMESTAMP_EXT:
+ params[0] = getExtensions().queryCounterBitsTimestamp;
+ break;
+ default:
+ UNREACHABLE();
+ params[0] = 0;
+ break;
+ }
+ break;
+ default:
+ UNREACHABLE();
+ return;
}
+}
- delete mFramebufferMap[0];
- mFramebufferMap[0] = buffer;
+Error Context::getQueryObjectiv(GLuint id, GLenum pname, GLint *params)
+{
+ return GetQueryObjectParameter(this, id, pname, params);
}
-Framebuffer *Context::getFramebuffer(unsigned int handle) const
+Error Context::getQueryObjectuiv(GLuint id, GLenum pname, GLuint *params)
{
- FramebufferMap::const_iterator framebuffer = mFramebufferMap.find(handle);
+ return GetQueryObjectParameter(this, id, pname, params);
+}
- if (framebuffer == mFramebufferMap.end())
- {
- return NULL;
- }
- else
- {
- return framebuffer->second;
- }
+Error Context::getQueryObjecti64v(GLuint id, GLenum pname, GLint64 *params)
+{
+ return GetQueryObjectParameter(this, id, pname, params);
+}
+
+Error Context::getQueryObjectui64v(GLuint id, GLenum pname, GLuint64 *params)
+{
+ return GetQueryObjectParameter(this, id, pname, params);
+}
+
+Framebuffer *Context::getFramebuffer(unsigned int handle) const
+{
+ auto framebufferIt = mFramebufferMap.find(handle);
+ return ((framebufferIt == mFramebufferMap.end()) ? nullptr : framebufferIt->second);
}
FenceNV *Context::getFenceNV(unsigned int handle)
@@ -727,11 +919,16 @@ Query *Context::getQuery(unsigned int handle, bool create, GLenum type)
}
}
+Query *Context::getQuery(GLuint handle) const
+{
+ auto iter = mQueryMap.find(handle);
+ return (iter != mQueryMap.end()) ? iter->second : nullptr;
+}
+
Texture *Context::getTargetTexture(GLenum target) const
{
ASSERT(ValidTextureTarget(this, target));
-
- return getSamplerTexture(mState.getActiveSampler(), target);
+ return mState.getTargetTexture(target);
}
Texture *Context::getSamplerTexture(unsigned int sampler, GLenum type) const
@@ -774,6 +971,9 @@ void Context::getFloatv(GLenum pname, GLfloat *params)
ASSERT(mExtensions.textureFilterAnisotropic);
*params = mExtensions.maxTextureAnisotropy;
break;
+ case GL_MAX_TEXTURE_LOD_BIAS:
+ *params = mCaps.maxLODBias;
+ break;
default:
mState.getFloatv(pname, params);
break;
@@ -796,7 +996,7 @@ void Context::getIntegerv(GLenum pname, GLint *params)
case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS: *params = mCaps.maxVertexTextureImageUnits; break;
case GL_MAX_TEXTURE_IMAGE_UNITS: *params = mCaps.maxTextureImageUnits; break;
case GL_MAX_FRAGMENT_UNIFORM_VECTORS: *params = mCaps.maxFragmentUniformVectors; break;
- case GL_MAX_FRAGMENT_UNIFORM_COMPONENTS: *params = mCaps.maxFragmentInputComponents; break;
+ case GL_MAX_FRAGMENT_UNIFORM_COMPONENTS: *params = mCaps.maxFragmentUniformComponents; break;
case GL_MAX_RENDERBUFFER_SIZE: *params = mCaps.maxRenderbufferSize; break;
case GL_MAX_COLOR_ATTACHMENTS_EXT: *params = mCaps.maxColorAttachments; break;
case GL_MAX_DRAW_BUFFERS_EXT: *params = mCaps.maxDrawBuffers; break;
@@ -811,6 +1011,10 @@ void Context::getIntegerv(GLenum pname, GLint *params)
case GL_MAX_VERTEX_UNIFORM_BLOCKS: *params = mCaps.maxVertexUniformBlocks; break;
case GL_MAX_FRAGMENT_UNIFORM_BLOCKS: *params = mCaps.maxFragmentUniformBlocks; break;
case GL_MAX_COMBINED_UNIFORM_BLOCKS: *params = mCaps.maxCombinedTextureImageUnits; break;
+ case GL_MAX_VERTEX_OUTPUT_COMPONENTS: *params = mCaps.maxVertexOutputComponents; break;
+ case GL_MAX_FRAGMENT_INPUT_COMPONENTS: *params = mCaps.maxFragmentInputComponents; break;
+ case GL_MIN_PROGRAM_TEXEL_OFFSET: *params = mCaps.minProgramTexelOffset; break;
+ case GL_MAX_PROGRAM_TEXEL_OFFSET: *params = mCaps.maxProgramTexelOffset; break;
case GL_MAJOR_VERSION: *params = mClientVersion; break;
case GL_MINOR_VERSION: *params = 0; break;
case GL_MAX_ELEMENTS_INDICES: *params = mCaps.maxElementsIndices; break;
@@ -818,8 +1022,10 @@ void Context::getIntegerv(GLenum pname, GLint *params)
case GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS: *params = mCaps.maxTransformFeedbackInterleavedComponents; break;
case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS: *params = mCaps.maxTransformFeedbackSeparateAttributes; break;
case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS: *params = mCaps.maxTransformFeedbackSeparateComponents; break;
- case GL_NUM_COMPRESSED_TEXTURE_FORMATS: *params = mCaps.compressedTextureFormats.size(); break;
- case GL_MAX_SAMPLES_ANGLE: *params = mExtensions.maxSamples; break;
+ case GL_NUM_COMPRESSED_TEXTURE_FORMATS:
+ *params = static_cast<GLint>(mCaps.compressedTextureFormats.size());
+ break;
+ case GL_MAX_SAMPLES_ANGLE: *params = mCaps.maxSamples; break;
case GL_MAX_VIEWPORT_DIMS:
{
params[0] = mCaps.maxViewportWidth;
@@ -833,13 +1039,13 @@ void Context::getIntegerv(GLenum pname, GLint *params)
*params = mResetStrategy;
break;
case GL_NUM_SHADER_BINARY_FORMATS:
- *params = mCaps.shaderBinaryFormats.size();
+ *params = static_cast<GLint>(mCaps.shaderBinaryFormats.size());
break;
case GL_SHADER_BINARY_FORMATS:
std::copy(mCaps.shaderBinaryFormats.begin(), mCaps.shaderBinaryFormats.end(), params);
break;
case GL_NUM_PROGRAM_BINARY_FORMATS:
- *params = mCaps.programBinaryFormats.size();
+ *params = static_cast<GLint>(mCaps.programBinaryFormats.size());
break;
case GL_PROGRAM_BINARY_FORMATS:
std::copy(mCaps.programBinaryFormats.begin(), mCaps.programBinaryFormats.end(), params);
@@ -847,6 +1053,26 @@ void Context::getIntegerv(GLenum pname, GLint *params)
case GL_NUM_EXTENSIONS:
*params = static_cast<GLint>(mExtensionStrings.size());
break;
+
+ // GL_KHR_debug
+ case GL_MAX_DEBUG_MESSAGE_LENGTH:
+ *params = mExtensions.maxDebugMessageLength;
+ break;
+ case GL_MAX_DEBUG_LOGGED_MESSAGES:
+ *params = mExtensions.maxDebugLoggedMessages;
+ break;
+ case GL_MAX_DEBUG_GROUP_STACK_DEPTH:
+ *params = mExtensions.maxDebugGroupStackDepth;
+ break;
+ case GL_MAX_LABEL_LENGTH:
+ *params = mExtensions.maxLabelLength;
+ break;
+
+ // GL_EXT_disjoint_timer_query
+ case GL_GPU_DISJOINT_EXT:
+ *params = mRenderer->getGPUDisjoint();
+ break;
+
default:
mState.getIntegerv(getData(), pname, params);
break;
@@ -874,17 +1100,27 @@ void Context::getInteger64v(GLenum pname, GLint64 *params)
case GL_MAX_SERVER_WAIT_TIMEOUT:
*params = mCaps.maxServerWaitTimeout;
break;
+
+ // GL_EXT_disjoint_timer_query
+ case GL_TIMESTAMP_EXT:
+ *params = mRenderer->getTimestamp();
+ break;
default:
UNREACHABLE();
break;
}
}
+void Context::getPointerv(GLenum pname, void **params) const
+{
+ mState.getPointerv(pname, params);
+}
+
bool Context::getIndexedIntegerv(GLenum target, GLuint index, GLint *data)
{
// Queries about context capabilities and maximums are answered by Context.
// Queries about current GL state values are answered by State.
- // Indexed integer queries all refer to current state, so this function is a
+ // Indexed integer queries all refer to current state, so this function is a
// mere passthrough.
return mState.getIndexedIntegerv(target, index, data);
}
@@ -893,7 +1129,7 @@ bool Context::getIndexedInteger64v(GLenum target, GLuint index, GLint64 *data)
{
// Queries about context capabilities and maximums are answered by Context.
// Queries about current GL state values are answered by State.
- // Indexed integer queries all refer to current state, so this function is a
+ // Indexed integer queries all refer to current state, so this function is a
// mere passthrough.
return mState.getIndexedInteger64v(target, index, data);
}
@@ -919,19 +1155,19 @@ bool Context::getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *nu
case GL_COMPRESSED_TEXTURE_FORMATS:
{
*type = GL_INT;
- *numParams = mCaps.compressedTextureFormats.size();
+ *numParams = static_cast<unsigned int>(mCaps.compressedTextureFormats.size());
}
return true;
case GL_PROGRAM_BINARY_FORMATS_OES:
{
*type = GL_INT;
- *numParams = mCaps.programBinaryFormats.size();
+ *numParams = static_cast<unsigned int>(mCaps.programBinaryFormats.size());
}
return true;
case GL_SHADER_BINARY_FORMATS:
{
*type = GL_INT;
- *numParams = mCaps.shaderBinaryFormats.size();
+ *numParams = static_cast<unsigned int>(mCaps.shaderBinaryFormats.size());
}
return true;
@@ -1019,20 +1255,6 @@ bool Context::getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *nu
}
}
return true;
- case GL_PIXEL_PACK_BUFFER_BINDING:
- case GL_PIXEL_UNPACK_BUFFER_BINDING:
- {
- if (mExtensions.pixelBufferObject)
- {
- *type = GL_INT;
- *numParams = 1;
- }
- else
- {
- return false;
- }
- }
- return true;
case GL_MAX_VIEWPORT_DIMS:
{
*type = GL_INT;
@@ -1103,6 +1325,87 @@ bool Context::getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *nu
*type = GL_FLOAT;
*numParams = 1;
return true;
+ case GL_TIMESTAMP_EXT:
+ if (!mExtensions.disjointTimerQuery)
+ {
+ return false;
+ }
+ *type = GL_INT_64_ANGLEX;
+ *numParams = 1;
+ return true;
+ case GL_GPU_DISJOINT_EXT:
+ if (!mExtensions.disjointTimerQuery)
+ {
+ return false;
+ }
+ *type = GL_INT;
+ *numParams = 1;
+ return true;
+ }
+
+ if (mExtensions.debug)
+ {
+ switch (pname)
+ {
+ case GL_DEBUG_LOGGED_MESSAGES:
+ case GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH:
+ case GL_DEBUG_GROUP_STACK_DEPTH:
+ case GL_MAX_DEBUG_MESSAGE_LENGTH:
+ case GL_MAX_DEBUG_LOGGED_MESSAGES:
+ case GL_MAX_DEBUG_GROUP_STACK_DEPTH:
+ case GL_MAX_LABEL_LENGTH:
+ *type = GL_INT;
+ *numParams = 1;
+ return true;
+
+ case GL_DEBUG_OUTPUT_SYNCHRONOUS:
+ case GL_DEBUG_OUTPUT:
+ *type = GL_BOOL;
+ *numParams = 1;
+ return true;
+ }
+ }
+
+ // Check for ES3.0+ parameter names which are also exposed as ES2 extensions
+ switch (pname)
+ {
+ case GL_PACK_ROW_LENGTH:
+ case GL_PACK_SKIP_ROWS:
+ case GL_PACK_SKIP_PIXELS:
+ if ((mClientVersion < 3) && !mExtensions.packSubimage)
+ {
+ return false;
+ }
+ *type = GL_INT;
+ *numParams = 1;
+ return true;
+ case GL_UNPACK_ROW_LENGTH:
+ case GL_UNPACK_SKIP_ROWS:
+ case GL_UNPACK_SKIP_PIXELS:
+ if ((mClientVersion < 3) && !mExtensions.unpackSubimage)
+ {
+ return false;
+ }
+ *type = GL_INT;
+ *numParams = 1;
+ return true;
+ case GL_VERTEX_ARRAY_BINDING:
+ if ((mClientVersion < 3) && !mExtensions.vertexArrayObject)
+ {
+ return false;
+ }
+ *type = GL_INT;
+ *numParams = 1;
+ return true;
+ case GL_PIXEL_PACK_BUFFER_BINDING:
+ case GL_PIXEL_UNPACK_BUFFER_BINDING:
+ if ((mClientVersion < 3) && !mExtensions.pixelBufferObject)
+ {
+ return false;
+ }
+ *type = GL_INT;
+ *numParams = 1;
+ return true;
}
if (mClientVersion < 3)
@@ -1117,6 +1420,7 @@ bool Context::getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *nu
case GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT:
case GL_UNIFORM_BUFFER_BINDING:
case GL_TRANSFORM_FEEDBACK_BINDING:
+ case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING:
case GL_COPY_READ_BUFFER_BINDING:
case GL_COPY_WRITE_BUFFER_BINDING:
case GL_TEXTURE_BINDING_3D:
@@ -1126,10 +1430,13 @@ bool Context::getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *nu
case GL_MAX_VERTEX_UNIFORM_BLOCKS:
case GL_MAX_FRAGMENT_UNIFORM_BLOCKS:
case GL_MAX_COMBINED_UNIFORM_BLOCKS:
+ case GL_MAX_VERTEX_OUTPUT_COMPONENTS:
+ case GL_MAX_FRAGMENT_INPUT_COMPONENTS:
case GL_MAX_VARYING_COMPONENTS:
- case GL_VERTEX_ARRAY_BINDING:
case GL_MAX_VERTEX_UNIFORM_COMPONENTS:
case GL_MAX_FRAGMENT_UNIFORM_COMPONENTS:
+ case GL_MIN_PROGRAM_TEXEL_OFFSET:
+ case GL_MAX_PROGRAM_TEXEL_OFFSET:
case GL_NUM_EXTENSIONS:
case GL_MAJOR_VERSION:
case GL_MINOR_VERSION:
@@ -1138,6 +1445,8 @@ bool Context::getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *nu
case GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS:
case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS:
case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS:
+ case GL_UNPACK_IMAGE_HEIGHT:
+ case GL_UNPACK_SKIP_IMAGES:
{
*type = GL_INT;
*numParams = 1;
@@ -1157,11 +1466,20 @@ bool Context::getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *nu
case GL_TRANSFORM_FEEDBACK_ACTIVE:
case GL_TRANSFORM_FEEDBACK_PAUSED:
+ case GL_PRIMITIVE_RESTART_FIXED_INDEX:
+ case GL_RASTERIZER_DISCARD:
{
*type = GL_BOOL;
*numParams = 1;
}
return true;
+
+ case GL_MAX_TEXTURE_LOD_BIAS:
+ {
+ *type = GL_FLOAT;
+ *numParams = 1;
+ }
+ return true;
}
return false;
@@ -1196,16 +1514,67 @@ bool Context::getIndexedQueryParameterInfo(GLenum target, GLenum *type, unsigned
return false;
}
-Error Context::drawArrays(GLenum mode, GLint first, GLsizei count, GLsizei instances)
+Error Context::drawArrays(GLenum mode, GLint first, GLsizei count)
{
- return mRenderer->drawArrays(getData(), mode, first, count, instances);
+ syncRendererState();
+ Error error = mRenderer->drawArrays(getData(), mode, first, count);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ MarkTransformFeedbackBufferUsage(mState.getCurrentTransformFeedback());
+
+ return Error(GL_NO_ERROR);
}
-Error Context::drawElements(GLenum mode, GLsizei count, GLenum type,
- const GLvoid *indices, GLsizei instances,
- const rx::RangeUI &indexRange)
+Error Context::drawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instanceCount)
{
- return mRenderer->drawElements(getData(), mode, count, type, indices, instances, indexRange);
+ syncRendererState();
+ Error error = mRenderer->drawArraysInstanced(getData(), mode, first, count, instanceCount);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ MarkTransformFeedbackBufferUsage(mState.getCurrentTransformFeedback());
+
+ return Error(GL_NO_ERROR);
+}
+
+Error Context::drawElements(GLenum mode,
+ GLsizei count,
+ GLenum type,
+ const GLvoid *indices,
+ const IndexRange &indexRange)
+{
+ syncRendererState();
+ return mRenderer->drawElements(getData(), mode, count, type, indices, indexRange);
+}
+
+Error Context::drawElementsInstanced(GLenum mode,
+ GLsizei count,
+ GLenum type,
+ const GLvoid *indices,
+ GLsizei instances,
+ const IndexRange &indexRange)
+{
+ syncRendererState();
+ return mRenderer->drawElementsInstanced(getData(), mode, count, type, indices, instances,
+ indexRange);
+}
+
+Error Context::drawRangeElements(GLenum mode,
+ GLuint start,
+ GLuint end,
+ GLsizei count,
+ GLenum type,
+ const GLvoid *indices,
+ const IndexRange &indexRange)
+{
+ syncRendererState();
+ return mRenderer->drawRangeElements(getData(), mode, start, end, count, type, indices,
+ indexRange);
}
Error Context::flush()
@@ -1218,11 +1587,36 @@ Error Context::finish()
return mRenderer->finish();
}
+void Context::insertEventMarker(GLsizei length, const char *marker)
+{
+ ASSERT(mRenderer);
+ mRenderer->insertEventMarker(length, marker);
+}
+
+void Context::pushGroupMarker(GLsizei length, const char *marker)
+{
+ ASSERT(mRenderer);
+ mRenderer->pushGroupMarker(length, marker);
+}
+
+void Context::popGroupMarker()
+{
+ ASSERT(mRenderer);
+ mRenderer->popGroupMarker();
+}
+
void Context::recordError(const Error &error)
{
if (error.isError())
{
mErrors.insert(error.getCode());
+
+ if (!error.getMessage().empty())
+ {
+ auto &debug = mState.getDebug();
+ debug.insertMessage(GL_DEBUG_SOURCE_API, GL_DEBUG_TYPE_ERROR, error.getID(),
+ GL_DEBUG_SEVERITY_HIGH, error.getMessage());
+ }
}
}
@@ -1275,14 +1669,9 @@ bool Context::isResetNotificationEnabled()
return (mResetStrategy == GL_LOSE_CONTEXT_ON_RESET_EXT);
}
-int Context::getClientVersion() const
+const egl::Config *Context::getConfig() const
{
- return mClientVersion;
-}
-
-EGLint Context::getConfigID() const
-{
- return mConfigID;
+ return mConfig;
}
EGLenum Context::getClientType() const
@@ -1292,22 +1681,73 @@ EGLenum Context::getClientType() const
EGLenum Context::getRenderBuffer() const
{
- return mRenderBuffer;
+ auto framebufferIt = mFramebufferMap.find(0);
+ if (framebufferIt != mFramebufferMap.end())
+ {
+ const Framebuffer *framebuffer = framebufferIt->second;
+ const FramebufferAttachment *backAttachment = framebuffer->getAttachment(GL_BACK);
+
+ ASSERT(backAttachment != nullptr);
+ return backAttachment->getSurface()->getRenderBuffer();
+ }
+ else
+ {
+ return EGL_NONE;
+ }
+}
+
+void Context::checkVertexArrayAllocation(GLuint vertexArray)
+{
+ // Only called after a prior call to Gen.
+ if (!getVertexArray(vertexArray))
+ {
+ VertexArray *vertexArrayObject =
+ new VertexArray(mRenderer, vertexArray, MAX_VERTEX_ATTRIBS);
+ mVertexArrayMap[vertexArray] = vertexArrayObject;
+ }
+}
+
+void Context::checkTransformFeedbackAllocation(GLuint transformFeedback)
+{
+ // Only called after a prior call to Gen.
+ if (!getTransformFeedback(transformFeedback))
+ {
+ TransformFeedback *transformFeedbackObject =
+ new TransformFeedback(mRenderer->createTransformFeedback(), transformFeedback, mCaps);
+ transformFeedbackObject->addRef();
+ mTransformFeedbackMap[transformFeedback] = transformFeedbackObject;
+ }
}
-const Caps &Context::getCaps() const
+Framebuffer *Context::checkFramebufferAllocation(GLuint framebuffer)
{
- return mCaps;
+ // Can be called from Bind without a prior call to Gen.
+ auto framebufferIt = mFramebufferMap.find(framebuffer);
+ bool neverCreated = framebufferIt == mFramebufferMap.end();
+ if (neverCreated || framebufferIt->second == nullptr)
+ {
+ Framebuffer *newFBO = new Framebuffer(mCaps, mRenderer, framebuffer);
+ if (neverCreated)
+ {
+ mFramebufferHandleAllocator.reserve(framebuffer);
+ mFramebufferMap[framebuffer] = newFBO;
+ return newFBO;
+ }
+
+ framebufferIt->second = newFBO;
+ }
+
+ return framebufferIt->second;
}
-const TextureCapsMap &Context::getTextureCaps() const
+bool Context::isVertexArrayGenerated(GLuint vertexArray)
{
- return mTextureCaps;
+ return mVertexArrayMap.find(vertexArray) != mVertexArrayMap.end();
}
-const Extensions &Context::getExtensions() const
+bool Context::isTransformFeedbackGenerated(GLuint transformFeedback)
{
- return mExtensions;
+ return mTransformFeedbackMap.find(transformFeedback) != mTransformFeedbackMap.end();
}
void Context::detachTexture(GLuint texture)
@@ -1321,20 +1761,15 @@ void Context::detachTexture(GLuint texture)
void Context::detachBuffer(GLuint buffer)
{
- // Buffer detachment is handled by Context, because the buffer must also be
- // attached from any VAOs in existence, and Context holds the VAO map.
+ // Simple pass-through to State's detachBuffer method, since
+ // only buffer attachments to container objects that are bound to the current context
+ // should be detached. And all those are available in State.
- // [OpenGL ES 2.0.24] section 2.9 page 22:
- // If a buffer object is deleted while it is bound, all bindings to that object in the current context
- // (i.e. in the thread that called Delete-Buffers) are reset to zero.
-
- mState.removeArrayBufferBinding(buffer);
-
- // mark as freed among the vertex array objects
- for (auto vaoIt = mVertexArrayMap.begin(); vaoIt != mVertexArrayMap.end(); vaoIt++)
- {
- vaoIt->second->detachBuffer(buffer);
- }
+ // [OpenGL ES 3.2] section 5.1.2 page 45:
+ // Attachments to unbound container objects, such as
+ // deletion of a buffer attached to a vertex array object which is not bound to the context,
+ // are not affected and continue to act as references on the deleted object
+ mState.detachBuffer(buffer);
}
void Context::detachFramebuffer(GLuint framebuffer)
@@ -1365,8 +1800,8 @@ void Context::detachRenderbuffer(GLuint renderbuffer)
void Context::detachVertexArray(GLuint vertexArray)
{
- // Vertex array detachment is handled by Context, because 0 is a valid
- // VAO, and a pointer to it must be passed from Context to State at
+ // Vertex array detachment is handled by Context, because 0 is a valid
+ // VAO, and a pointer to it must be passed from Context to State at
// binding time.
// [OpenGL ES 3.0.2] section 2.10 page 43:
@@ -1390,7 +1825,7 @@ void Context::detachSampler(GLuint sampler)
void Context::setVertexAttribDivisor(GLuint index, GLuint divisor)
{
- mState.getVertexArray()->setVertexAttribDivisor(index, divisor);
+ mState.setVertexAttribDivisor(index, divisor);
}
void Context::samplerParameteri(GLuint sampler, GLenum pname, GLint param)
@@ -1400,19 +1835,22 @@ void Context::samplerParameteri(GLuint sampler, GLenum pname, GLint param)
Sampler *samplerObject = getSampler(sampler);
ASSERT(samplerObject);
+ // clang-format off
switch (pname)
{
- case GL_TEXTURE_MIN_FILTER: samplerObject->setMinFilter(static_cast<GLenum>(param)); break;
- case GL_TEXTURE_MAG_FILTER: samplerObject->setMagFilter(static_cast<GLenum>(param)); break;
- case GL_TEXTURE_WRAP_S: samplerObject->setWrapS(static_cast<GLenum>(param)); break;
- case GL_TEXTURE_WRAP_T: samplerObject->setWrapT(static_cast<GLenum>(param)); break;
- case GL_TEXTURE_WRAP_R: samplerObject->setWrapR(static_cast<GLenum>(param)); break;
- case GL_TEXTURE_MIN_LOD: samplerObject->setMinLod(static_cast<GLfloat>(param)); break;
- case GL_TEXTURE_MAX_LOD: samplerObject->setMaxLod(static_cast<GLfloat>(param)); break;
- case GL_TEXTURE_COMPARE_MODE: samplerObject->setComparisonMode(static_cast<GLenum>(param)); break;
- case GL_TEXTURE_COMPARE_FUNC: samplerObject->setComparisonFunc(static_cast<GLenum>(param)); break;
- default: UNREACHABLE(); break;
+ case GL_TEXTURE_MIN_FILTER: samplerObject->setMinFilter(static_cast<GLenum>(param)); break;
+ case GL_TEXTURE_MAG_FILTER: samplerObject->setMagFilter(static_cast<GLenum>(param)); break;
+ case GL_TEXTURE_WRAP_S: samplerObject->setWrapS(static_cast<GLenum>(param)); break;
+ case GL_TEXTURE_WRAP_T: samplerObject->setWrapT(static_cast<GLenum>(param)); break;
+ case GL_TEXTURE_WRAP_R: samplerObject->setWrapR(static_cast<GLenum>(param)); break;
+ case GL_TEXTURE_MAX_ANISOTROPY_EXT: samplerObject->setMaxAnisotropy(std::min(static_cast<GLfloat>(param), getExtensions().maxTextureAnisotropy)); break;
+ case GL_TEXTURE_MIN_LOD: samplerObject->setMinLod(static_cast<GLfloat>(param)); break;
+ case GL_TEXTURE_MAX_LOD: samplerObject->setMaxLod(static_cast<GLfloat>(param)); break;
+ case GL_TEXTURE_COMPARE_MODE: samplerObject->setCompareMode(static_cast<GLenum>(param)); break;
+ case GL_TEXTURE_COMPARE_FUNC: samplerObject->setCompareFunc(static_cast<GLenum>(param)); break;
+ default: UNREACHABLE(); break;
}
+ // clang-format on
}
void Context::samplerParameterf(GLuint sampler, GLenum pname, GLfloat param)
@@ -1422,19 +1860,22 @@ void Context::samplerParameterf(GLuint sampler, GLenum pname, GLfloat param)
Sampler *samplerObject = getSampler(sampler);
ASSERT(samplerObject);
+ // clang-format off
switch (pname)
{
- case GL_TEXTURE_MIN_FILTER: samplerObject->setMinFilter(uiround<GLenum>(param)); break;
- case GL_TEXTURE_MAG_FILTER: samplerObject->setMagFilter(uiround<GLenum>(param)); break;
- case GL_TEXTURE_WRAP_S: samplerObject->setWrapS(uiround<GLenum>(param)); break;
- case GL_TEXTURE_WRAP_T: samplerObject->setWrapT(uiround<GLenum>(param)); break;
- case GL_TEXTURE_WRAP_R: samplerObject->setWrapR(uiround<GLenum>(param)); break;
- case GL_TEXTURE_MIN_LOD: samplerObject->setMinLod(param); break;
- case GL_TEXTURE_MAX_LOD: samplerObject->setMaxLod(param); break;
- case GL_TEXTURE_COMPARE_MODE: samplerObject->setComparisonMode(uiround<GLenum>(param)); break;
- case GL_TEXTURE_COMPARE_FUNC: samplerObject->setComparisonFunc(uiround<GLenum>(param)); break;
- default: UNREACHABLE(); break;
+ case GL_TEXTURE_MIN_FILTER: samplerObject->setMinFilter(uiround<GLenum>(param)); break;
+ case GL_TEXTURE_MAG_FILTER: samplerObject->setMagFilter(uiround<GLenum>(param)); break;
+ case GL_TEXTURE_WRAP_S: samplerObject->setWrapS(uiround<GLenum>(param)); break;
+ case GL_TEXTURE_WRAP_T: samplerObject->setWrapT(uiround<GLenum>(param)); break;
+ case GL_TEXTURE_WRAP_R: samplerObject->setWrapR(uiround<GLenum>(param)); break;
+ case GL_TEXTURE_MAX_ANISOTROPY_EXT: samplerObject->setMaxAnisotropy(std::min(param, getExtensions().maxTextureAnisotropy)); break;
+ case GL_TEXTURE_MIN_LOD: samplerObject->setMinLod(param); break;
+ case GL_TEXTURE_MAX_LOD: samplerObject->setMaxLod(param); break;
+ case GL_TEXTURE_COMPARE_MODE: samplerObject->setCompareMode(uiround<GLenum>(param)); break;
+ case GL_TEXTURE_COMPARE_FUNC: samplerObject->setCompareFunc(uiround<GLenum>(param)); break;
+ default: UNREACHABLE(); break;
}
+ // clang-format on
}
GLint Context::getSamplerParameteri(GLuint sampler, GLenum pname)
@@ -1444,19 +1885,22 @@ GLint Context::getSamplerParameteri(GLuint sampler, GLenum pname)
Sampler *samplerObject = getSampler(sampler);
ASSERT(samplerObject);
+ // clang-format off
switch (pname)
{
- case GL_TEXTURE_MIN_FILTER: return static_cast<GLint>(samplerObject->getMinFilter());
- case GL_TEXTURE_MAG_FILTER: return static_cast<GLint>(samplerObject->getMagFilter());
- case GL_TEXTURE_WRAP_S: return static_cast<GLint>(samplerObject->getWrapS());
- case GL_TEXTURE_WRAP_T: return static_cast<GLint>(samplerObject->getWrapT());
- case GL_TEXTURE_WRAP_R: return static_cast<GLint>(samplerObject->getWrapR());
- case GL_TEXTURE_MIN_LOD: return uiround<GLint>(samplerObject->getMinLod());
- case GL_TEXTURE_MAX_LOD: return uiround<GLint>(samplerObject->getMaxLod());
- case GL_TEXTURE_COMPARE_MODE: return static_cast<GLint>(samplerObject->getComparisonMode());
- case GL_TEXTURE_COMPARE_FUNC: return static_cast<GLint>(samplerObject->getComparisonFunc());
- default: UNREACHABLE(); return 0;
+ case GL_TEXTURE_MIN_FILTER: return static_cast<GLint>(samplerObject->getMinFilter());
+ case GL_TEXTURE_MAG_FILTER: return static_cast<GLint>(samplerObject->getMagFilter());
+ case GL_TEXTURE_WRAP_S: return static_cast<GLint>(samplerObject->getWrapS());
+ case GL_TEXTURE_WRAP_T: return static_cast<GLint>(samplerObject->getWrapT());
+ case GL_TEXTURE_WRAP_R: return static_cast<GLint>(samplerObject->getWrapR());
+ case GL_TEXTURE_MAX_ANISOTROPY_EXT: return static_cast<GLint>(samplerObject->getMaxAnisotropy());
+ case GL_TEXTURE_MIN_LOD: return uiround<GLint>(samplerObject->getMinLod());
+ case GL_TEXTURE_MAX_LOD: return uiround<GLint>(samplerObject->getMaxLod());
+ case GL_TEXTURE_COMPARE_MODE: return static_cast<GLint>(samplerObject->getCompareMode());
+ case GL_TEXTURE_COMPARE_FUNC: return static_cast<GLint>(samplerObject->getCompareFunc());
+ default: UNREACHABLE(); return 0;
}
+ // clang-format on
}
GLfloat Context::getSamplerParameterf(GLuint sampler, GLenum pname)
@@ -1466,19 +1910,22 @@ GLfloat Context::getSamplerParameterf(GLuint sampler, GLenum pname)
Sampler *samplerObject = getSampler(sampler);
ASSERT(samplerObject);
+ // clang-format off
switch (pname)
{
- case GL_TEXTURE_MIN_FILTER: return static_cast<GLfloat>(samplerObject->getMinFilter());
- case GL_TEXTURE_MAG_FILTER: return static_cast<GLfloat>(samplerObject->getMagFilter());
- case GL_TEXTURE_WRAP_S: return static_cast<GLfloat>(samplerObject->getWrapS());
- case GL_TEXTURE_WRAP_T: return static_cast<GLfloat>(samplerObject->getWrapT());
- case GL_TEXTURE_WRAP_R: return static_cast<GLfloat>(samplerObject->getWrapR());
- case GL_TEXTURE_MIN_LOD: return samplerObject->getMinLod();
- case GL_TEXTURE_MAX_LOD: return samplerObject->getMaxLod();
- case GL_TEXTURE_COMPARE_MODE: return static_cast<GLfloat>(samplerObject->getComparisonMode());
- case GL_TEXTURE_COMPARE_FUNC: return static_cast<GLfloat>(samplerObject->getComparisonFunc());
- default: UNREACHABLE(); return 0;
+ case GL_TEXTURE_MIN_FILTER: return static_cast<GLfloat>(samplerObject->getMinFilter());
+ case GL_TEXTURE_MAG_FILTER: return static_cast<GLfloat>(samplerObject->getMagFilter());
+ case GL_TEXTURE_WRAP_S: return static_cast<GLfloat>(samplerObject->getWrapS());
+ case GL_TEXTURE_WRAP_T: return static_cast<GLfloat>(samplerObject->getWrapT());
+ case GL_TEXTURE_WRAP_R: return static_cast<GLfloat>(samplerObject->getWrapR());
+ case GL_TEXTURE_MAX_ANISOTROPY_EXT: return samplerObject->getMaxAnisotropy();
+ case GL_TEXTURE_MIN_LOD: return samplerObject->getMinLod();
+ case GL_TEXTURE_MAX_LOD: return samplerObject->getMaxLod();
+ case GL_TEXTURE_COMPARE_MODE: return static_cast<GLfloat>(samplerObject->getCompareMode());
+ case GL_TEXTURE_COMPARE_FUNC: return static_cast<GLfloat>(samplerObject->getCompareFunc());
+ default: UNREACHABLE(); return 0;
}
+ // clang-format on
}
void Context::initRendererString()
@@ -1526,6 +1973,8 @@ void Context::initCaps(GLuint clientVersion)
mExtensions = mRenderer->getRendererExtensions();
+ mLimitations = mRenderer->getRendererLimitations();
+
if (clientVersion < 3)
{
// Disable ES3+ extensions
@@ -1538,6 +1987,13 @@ void Context::initCaps(GLuint clientVersion)
//mExtensions.sRGB = false;
}
+ // Explicitly enable GL_KHR_debug
+ mExtensions.debug = true;
+ mExtensions.maxDebugMessageLength = 1024;
+ mExtensions.maxDebugLoggedMessages = 1024;
+ mExtensions.maxDebugGroupStackDepth = 1024;
+ mExtensions.maxLabelLength = 1024;
+
// Apply implementation limits
mCaps.maxVertexAttributes = std::min<GLuint>(mCaps.maxVertexAttributes, MAX_VERTEX_ATTRIBS);
mCaps.maxVertexUniformBlocks = std::min<GLuint>(mCaps.maxVertexUniformBlocks, IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS);
@@ -1545,7 +2001,6 @@ void Context::initCaps(GLuint clientVersion)
mCaps.maxFragmentInputComponents = std::min<GLuint>(mCaps.maxFragmentInputComponents, IMPLEMENTATION_MAX_VARYING_VECTORS * 4);
- GLuint maxSamples = 0;
mCaps.compressedTextureFormats.clear();
const TextureCapsMap &rendererFormats = mRenderer->getRendererTextureCaps();
@@ -1556,17 +2011,21 @@ void Context::initCaps(GLuint clientVersion)
const InternalFormat &formatInfo = GetInternalFormatInfo(format);
- // Update the format caps based on the client version and extensions
- formatCaps.texturable = formatInfo.textureSupport(clientVersion, mExtensions);
- formatCaps.renderable = formatInfo.renderSupport(clientVersion, mExtensions);
- formatCaps.filterable = formatInfo.filterSupport(clientVersion, mExtensions);
+ // Update the format caps based on the client version and extensions.
+ // Caps are AND'd with the renderer caps because some core formats are still unsupported in
+ // ES3.
+ formatCaps.texturable =
+ formatCaps.texturable && formatInfo.textureSupport(clientVersion, mExtensions);
+ formatCaps.renderable =
+ formatCaps.renderable && formatInfo.renderSupport(clientVersion, mExtensions);
+ formatCaps.filterable =
+ formatCaps.filterable && formatInfo.filterSupport(clientVersion, mExtensions);
// OpenGL ES does not support multisampling with integer formats
if (!formatInfo.renderSupport || formatInfo.componentType == GL_INT || formatInfo.componentType == GL_UNSIGNED_INT)
{
formatCaps.sampleCounts.clear();
}
- maxSamples = std::max(maxSamples, formatCaps.getMaxSamples());
if (formatCaps.texturable && formatInfo.compressed)
{
@@ -1575,13 +2034,391 @@ void Context::initCaps(GLuint clientVersion)
mTextureCaps.insert(format, formatCaps);
}
+}
+
+void Context::syncRendererState()
+{
+ const State::DirtyBits &dirtyBits = mState.getDirtyBits();
+ mRenderer->syncState(mState, dirtyBits);
+ mState.clearDirtyBits();
+ mState.syncDirtyObjects();
+}
+
+void Context::syncRendererState(const State::DirtyBits &bitMask)
+{
+ const State::DirtyBits &dirtyBits = (mState.getDirtyBits() & bitMask);
+ mRenderer->syncState(mState, dirtyBits);
+ mState.clearDirtyBits(dirtyBits);
+
+ // TODO(jmadill): Filter objects by bitMask somehow?
+ mState.syncDirtyObjects();
+}
+
+void Context::blitFramebuffer(GLint srcX0,
+ GLint srcY0,
+ GLint srcX1,
+ GLint srcY1,
+ GLint dstX0,
+ GLint dstY0,
+ GLint dstX1,
+ GLint dstY1,
+ GLbitfield mask,
+ GLenum filter)
+{
+ Framebuffer *readFramebuffer = mState.getReadFramebuffer();
+ ASSERT(readFramebuffer);
+
+ Framebuffer *drawFramebuffer = mState.getDrawFramebuffer();
+ ASSERT(drawFramebuffer);
+
+ Rectangle srcArea(srcX0, srcY0, srcX1 - srcX0, srcY1 - srcY0);
+ Rectangle dstArea(dstX0, dstY0, dstX1 - dstX0, dstY1 - dstY0);
+
+ syncRendererState(mState.blitStateBitMask());
+
+ Error error = drawFramebuffer->blit(mState, srcArea, dstArea, mask, filter, readFramebuffer);
+ if (error.isError())
+ {
+ recordError(error);
+ return;
+ }
+}
+
+void Context::clear(GLbitfield mask)
+{
+ // Sync the clear state
+ syncRendererState(mState.clearStateBitMask());
+
+ Error error = mState.getDrawFramebuffer()->clear(mData, mask);
+ if (error.isError())
+ {
+ recordError(error);
+ }
+}
+
+void Context::clearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat *values)
+{
+ // Sync the clear state
+ syncRendererState(mState.clearStateBitMask());
+
+ Error error = mState.getDrawFramebuffer()->clearBufferfv(mData, buffer, drawbuffer, values);
+ if (error.isError())
+ {
+ recordError(error);
+ }
+}
+
+void Context::clearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint *values)
+{
+ // Sync the clear state
+ syncRendererState(mState.clearStateBitMask());
+
+ Error error = mState.getDrawFramebuffer()->clearBufferuiv(mData, buffer, drawbuffer, values);
+ if (error.isError())
+ {
+ recordError(error);
+ }
+}
+
+void Context::clearBufferiv(GLenum buffer, GLint drawbuffer, const GLint *values)
+{
+ // Sync the clear state
+ syncRendererState(mState.clearStateBitMask());
+
+ Error error = mState.getDrawFramebuffer()->clearBufferiv(mData, buffer, drawbuffer, values);
+ if (error.isError())
+ {
+ recordError(error);
+ }
+}
+
+void Context::clearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil)
+{
+ Framebuffer *framebufferObject = mState.getDrawFramebuffer();
+ ASSERT(framebufferObject);
+
+ // If a buffer is not present, the clear has no effect
+ if (framebufferObject->getDepthbuffer() == nullptr &&
+ framebufferObject->getStencilbuffer() == nullptr)
+ {
+ return;
+ }
+
+ // Sync the clear state
+ syncRendererState(mState.clearStateBitMask());
+
+ Error error = framebufferObject->clearBufferfi(mData, buffer, drawbuffer, depth, stencil);
+ if (error.isError())
+ {
+ recordError(error);
+ }
+}
+
+void Context::readPixels(GLint x,
+ GLint y,
+ GLsizei width,
+ GLsizei height,
+ GLenum format,
+ GLenum type,
+ GLvoid *pixels)
+{
+ // Sync pack state
+ syncRendererState(mState.packStateBitMask());
+
+ Framebuffer *framebufferObject = mState.getReadFramebuffer();
+ ASSERT(framebufferObject);
+
+ Rectangle area(x, y, width, height);
+ Error error = framebufferObject->readPixels(mState, area, format, type, pixels);
+ if (error.isError())
+ {
+ recordError(error);
+ }
+}
+
+void Context::copyTexImage2D(GLenum target,
+ GLint level,
+ GLenum internalformat,
+ GLint x,
+ GLint y,
+ GLsizei width,
+ GLsizei height,
+ GLint border)
+{
+ // Only sync the read FBO
+ mState.syncDirtyObject(GL_READ_FRAMEBUFFER);
+
+ Rectangle sourceArea(x, y, width, height);
+
+ const Framebuffer *framebuffer = mState.getReadFramebuffer();
+ Texture *texture =
+ getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target);
+ Error error = texture->copyImage(target, level, sourceArea, internalformat, framebuffer);
+ if (error.isError())
+ {
+ recordError(error);
+ }
+}
+
+void Context::copyTexSubImage2D(GLenum target,
+ GLint level,
+ GLint xoffset,
+ GLint yoffset,
+ GLint x,
+ GLint y,
+ GLsizei width,
+ GLsizei height)
+{
+ // Only sync the read FBO
+ mState.syncDirtyObject(GL_READ_FRAMEBUFFER);
+
+ Offset destOffset(xoffset, yoffset, 0);
+ Rectangle sourceArea(x, y, width, height);
+
+ const Framebuffer *framebuffer = mState.getReadFramebuffer();
+ Texture *texture =
+ getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target);
+ Error error = texture->copySubImage(target, level, destOffset, sourceArea, framebuffer);
+ if (error.isError())
+ {
+ recordError(error);
+ }
+}
+
+void Context::copyTexSubImage3D(GLenum target,
+ GLint level,
+ GLint xoffset,
+ GLint yoffset,
+ GLint zoffset,
+ GLint x,
+ GLint y,
+ GLsizei width,
+ GLsizei height)
+{
+ // Only sync the read FBO
+ mState.syncDirtyObject(GL_READ_FRAMEBUFFER);
+
+ Offset destOffset(xoffset, yoffset, zoffset);
+ Rectangle sourceArea(x, y, width, height);
+
+ const Framebuffer *framebuffer = mState.getReadFramebuffer();
+ Texture *texture = getTargetTexture(target);
+ Error error = texture->copySubImage(target, level, destOffset, sourceArea, framebuffer);
+ if (error.isError())
+ {
+ recordError(error);
+ }
+}
+
+void Context::framebufferTexture2D(GLenum target,
+ GLenum attachment,
+ GLenum textarget,
+ GLuint texture,
+ GLint level)
+{
+ Framebuffer *framebuffer = mState.getTargetFramebuffer(target);
+ ASSERT(framebuffer);
+
+ if (texture != 0)
+ {
+ Texture *textureObj = getTexture(texture);
+
+ ImageIndex index = ImageIndex::MakeInvalid();
+
+ if (textarget == GL_TEXTURE_2D)
+ {
+ index = ImageIndex::Make2D(level);
+ }
+ else
+ {
+ ASSERT(IsCubeMapTextureTarget(textarget));
+ index = ImageIndex::MakeCube(textarget, level);
+ }
+
+ framebuffer->setAttachment(GL_TEXTURE, attachment, index, textureObj);
+ }
+ else
+ {
+ framebuffer->resetAttachment(attachment);
+ }
+
+ mState.setObjectDirty(target);
+}
+
+void Context::framebufferRenderbuffer(GLenum target,
+ GLenum attachment,
+ GLenum renderbuffertarget,
+ GLuint renderbuffer)
+{
+ Framebuffer *framebuffer = mState.getTargetFramebuffer(target);
+ ASSERT(framebuffer);
+
+ if (renderbuffer != 0)
+ {
+ Renderbuffer *renderbufferObject = getRenderbuffer(renderbuffer);
+ framebuffer->setAttachment(GL_RENDERBUFFER, attachment, gl::ImageIndex::MakeInvalid(),
+ renderbufferObject);
+ }
+ else
+ {
+ framebuffer->resetAttachment(attachment);
+ }
- mExtensions.maxSamples = maxSamples;
+ mState.setObjectDirty(target);
}
-Data Context::getData() const
+void Context::framebufferTextureLayer(GLenum target,
+ GLenum attachment,
+ GLuint texture,
+ GLint level,
+ GLint layer)
{
- return Data(mClientVersion, mState, mCaps, mTextureCaps, mExtensions, mResourceManager);
+ Framebuffer *framebuffer = mState.getTargetFramebuffer(target);
+ ASSERT(framebuffer);
+
+ if (texture != 0)
+ {
+ Texture *textureObject = getTexture(texture);
+
+ ImageIndex index = ImageIndex::MakeInvalid();
+
+ if (textureObject->getTarget() == GL_TEXTURE_3D)
+ {
+ index = ImageIndex::Make3D(level, layer);
+ }
+ else
+ {
+ ASSERT(textureObject->getTarget() == GL_TEXTURE_2D_ARRAY);
+ index = ImageIndex::Make2DArray(level, layer);
+ }
+
+ framebuffer->setAttachment(GL_TEXTURE, attachment, index, textureObject);
+ }
+ else
+ {
+ framebuffer->resetAttachment(attachment);
+ }
+
+ mState.setObjectDirty(target);
+}
+
+void Context::drawBuffers(GLsizei n, const GLenum *bufs)
+{
+ Framebuffer *framebuffer = mState.getDrawFramebuffer();
+ ASSERT(framebuffer);
+ framebuffer->setDrawBuffers(n, bufs);
+ mState.setObjectDirty(GL_DRAW_FRAMEBUFFER);
}
+void Context::readBuffer(GLenum mode)
+{
+ Framebuffer *readFBO = mState.getReadFramebuffer();
+ readFBO->setReadBuffer(mode);
+ mState.setObjectDirty(GL_READ_FRAMEBUFFER);
}
+
+void Context::discardFramebuffer(GLenum target, GLsizei numAttachments, const GLenum *attachments)
+{
+ // Only sync the FBO
+ mState.syncDirtyObject(target);
+
+ Framebuffer *framebuffer = mState.getTargetFramebuffer(target);
+ ASSERT(framebuffer);
+
+ // The specification isn't clear what should be done when the framebuffer isn't complete.
+ // We leave it up to the framebuffer implementation to decide what to do.
+ Error error = framebuffer->discard(numAttachments, attachments);
+ if (error.isError())
+ {
+ recordError(error);
+ }
+}
+
+void Context::invalidateFramebuffer(GLenum target,
+ GLsizei numAttachments,
+ const GLenum *attachments)
+{
+ // Only sync the FBO
+ mState.syncDirtyObject(target);
+
+ Framebuffer *framebuffer = mState.getTargetFramebuffer(target);
+ ASSERT(framebuffer);
+
+ if (framebuffer->checkStatus(mData) == GL_FRAMEBUFFER_COMPLETE)
+ {
+ Error error = framebuffer->invalidate(numAttachments, attachments);
+ if (error.isError())
+ {
+ recordError(error);
+ return;
+ }
+ }
+}
+
+void Context::invalidateSubFramebuffer(GLenum target,
+ GLsizei numAttachments,
+ const GLenum *attachments,
+ GLint x,
+ GLint y,
+ GLsizei width,
+ GLsizei height)
+{
+ // Only sync the FBO
+ mState.syncDirtyObject(target);
+
+ Framebuffer *framebuffer = mState.getTargetFramebuffer(target);
+ ASSERT(framebuffer);
+
+ if (framebuffer->checkStatus(mData) == GL_FRAMEBUFFER_COMPLETE)
+ {
+ Rectangle area(x, y, width, height);
+ Error error = framebuffer->invalidateSub(numAttachments, attachments, area);
+ if (error.isError())
+ {
+ recordError(error);
+ return;
+ }
+ }
+}
+
+} // namespace gl
diff --git a/src/3rdparty/angle/src/libANGLE/Context.h b/src/3rdparty/angle/src/libANGLE/Context.h
index eeada43355..6b82eb7cb9 100644
--- a/src/3rdparty/angle/src/libANGLE/Context.h
+++ b/src/3rdparty/angle/src/libANGLE/Context.h
@@ -33,6 +33,7 @@ class Renderer;
namespace egl
{
+class AttributeMap;
class Surface;
struct Config;
}
@@ -55,19 +56,23 @@ class VertexArray;
class Sampler;
class TransformFeedback;
-class Context final : angle::NonCopyable
+class Context final : public ValidationContext
{
public:
- Context(const egl::Config *config, int clientVersion, const Context *shareContext, rx::Renderer *renderer, bool notifyResets, bool robustAccess);
+ Context(const egl::Config *config,
+ const Context *shareContext,
+ rx::Renderer *renderer,
+ const egl::AttributeMap &attribs);
virtual ~Context();
void makeCurrent(egl::Surface *surface);
+ void releaseSurface();
virtual void markContextLost();
bool isContextLost();
- // These create and destroy methods are merely pass-throughs to
+ // These create and destroy methods are merely pass-throughs to
// ResourceManager, which owns these object types
GLuint createBuffer();
GLuint createShader(GLenum type);
@@ -94,7 +99,7 @@ class Context final : angle::NonCopyable
// NV Fences are owned by the Context.
GLuint createFenceNV();
void deleteFenceNV(GLuint fence);
-
+
// Queries are owned by the Context;
GLuint createQuery();
void deleteQuery(GLuint query);
@@ -106,8 +111,8 @@ class Context final : angle::NonCopyable
void bindArrayBuffer(GLuint buffer);
void bindElementArrayBuffer(GLuint buffer);
void bindTexture(GLenum target, GLuint handle);
- void bindReadFramebuffer(GLuint framebuffer);
- void bindDrawFramebuffer(GLuint framebuffer);
+ void bindReadFramebuffer(GLuint framebufferHandle);
+ void bindDrawFramebuffer(GLuint framebufferHandle);
void bindRenderbuffer(GLuint renderbuffer);
void bindVertexArray(GLuint vertexArray);
void bindSampler(GLuint textureUnit, GLuint sampler);
@@ -124,8 +129,12 @@ class Context final : angle::NonCopyable
Error beginQuery(GLenum target, GLuint query);
Error endQuery(GLenum target);
-
- void setFramebufferZero(Framebuffer *framebuffer);
+ Error queryCounter(GLuint id, GLenum target);
+ void getQueryiv(GLenum target, GLenum pname, GLint *params);
+ Error getQueryObjectiv(GLuint id, GLenum pname, GLint *params);
+ Error getQueryObjectuiv(GLuint id, GLenum pname, GLuint *params);
+ Error getQueryObjecti64v(GLuint id, GLenum pname, GLint64 *params);
+ Error getQueryObjectui64v(GLuint id, GLenum pname, GLuint64 *params);
void setVertexAttribDivisor(GLuint index, GLuint divisor);
@@ -134,18 +143,21 @@ class Context final : angle::NonCopyable
GLint getSamplerParameteri(GLuint sampler, GLenum pname);
GLfloat getSamplerParameterf(GLuint sampler, GLenum pname);
- Buffer *getBuffer(GLuint handle);
+ Buffer *getBuffer(GLuint handle) const;
FenceNV *getFenceNV(GLuint handle);
FenceSync *getFenceSync(GLsync handle) const;
Shader *getShader(GLuint handle) const;
Program *getProgram(GLuint handle) const;
Texture *getTexture(GLuint handle) const;
Framebuffer *getFramebuffer(GLuint handle) const;
- Renderbuffer *getRenderbuffer(GLuint handle);
+ Renderbuffer *getRenderbuffer(GLuint handle) const;
VertexArray *getVertexArray(GLuint handle) const;
Sampler *getSampler(GLuint handle) const;
Query *getQuery(GLuint handle, bool create, GLenum type);
+ Query *getQuery(GLuint handle) const;
TransformFeedback *getTransformFeedback(GLuint handle) const;
+ LabeledObject *getLabeledObject(GLenum identifier, GLuint name) const;
+ LabeledObject *getLabeledObjectFromPtr(const void *ptr) const;
Texture *getTargetTexture(GLenum target) const;
Texture *getSamplerTexture(unsigned int sampler, GLenum type) const;
@@ -154,10 +166,14 @@ class Context final : angle::NonCopyable
bool isSampler(GLuint samplerName) const;
+ bool isVertexArrayGenerated(GLuint vertexArray);
+ bool isTransformFeedbackGenerated(GLuint vertexArray);
+
void getBooleanv(GLenum pname, GLboolean *params);
void getFloatv(GLenum pname, GLfloat *params);
void getIntegerv(GLenum pname, GLint *params);
void getInteger64v(GLenum pname, GLint64 *params);
+ void getPointerv(GLenum pname, void **params) const;
bool getIndexedIntegerv(GLenum target, GLuint index, GLint *data);
bool getIndexedInteger64v(GLenum target, GLuint index, GLint64 *data);
@@ -165,29 +181,128 @@ class Context final : angle::NonCopyable
bool getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *numParams);
bool getIndexedQueryParameterInfo(GLenum target, GLenum *type, unsigned int *numParams);
- Error drawArrays(GLenum mode, GLint first, GLsizei count, GLsizei instances);
- Error drawElements(GLenum mode, GLsizei count, GLenum type,
- const GLvoid *indices, GLsizei instances,
- const rx::RangeUI &indexRange);
+ void clear(GLbitfield mask);
+ void clearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat *values);
+ void clearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint *values);
+ void clearBufferiv(GLenum buffer, GLint drawbuffer, const GLint *values);
+ void clearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);
+
+ Error drawArrays(GLenum mode, GLint first, GLsizei count);
+ Error drawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instanceCount);
+
+ Error drawElements(GLenum mode,
+ GLsizei count,
+ GLenum type,
+ const GLvoid *indices,
+ const IndexRange &indexRange);
+ Error drawElementsInstanced(GLenum mode,
+ GLsizei count,
+ GLenum type,
+ const GLvoid *indices,
+ GLsizei instances,
+ const IndexRange &indexRange);
+ Error drawRangeElements(GLenum mode,
+ GLuint start,
+ GLuint end,
+ GLsizei count,
+ GLenum type,
+ const GLvoid *indices,
+ const IndexRange &indexRange);
+
+ void blitFramebuffer(GLint srcX0,
+ GLint srcY0,
+ GLint srcX1,
+ GLint srcY1,
+ GLint dstX0,
+ GLint dstY0,
+ GLint dstX1,
+ GLint dstY1,
+ GLbitfield mask,
+ GLenum filter);
+
+ void readPixels(GLint x,
+ GLint y,
+ GLsizei width,
+ GLsizei height,
+ GLenum format,
+ GLenum type,
+ GLvoid *pixels);
+
+ void copyTexImage2D(GLenum target,
+ GLint level,
+ GLenum internalformat,
+ GLint x,
+ GLint y,
+ GLsizei width,
+ GLsizei height,
+ GLint border);
+
+ void copyTexSubImage2D(GLenum target,
+ GLint level,
+ GLint xoffset,
+ GLint yoffset,
+ GLint x,
+ GLint y,
+ GLsizei width,
+ GLsizei height);
+
+ void copyTexSubImage3D(GLenum target,
+ GLint level,
+ GLint xoffset,
+ GLint yoffset,
+ GLint zoffset,
+ GLint x,
+ GLint y,
+ GLsizei width,
+ GLsizei height);
+
+ void framebufferTexture2D(GLenum target,
+ GLenum attachment,
+ GLenum textarget,
+ GLuint texture,
+ GLint level);
+
+ void framebufferRenderbuffer(GLenum target,
+ GLenum attachment,
+ GLenum renderbuffertarget,
+ GLuint renderbuffer);
+
+ void framebufferTextureLayer(GLenum target,
+ GLenum attachment,
+ GLuint texture,
+ GLint level,
+ GLint layer);
+
+ void drawBuffers(GLsizei n, const GLenum *bufs);
+ void readBuffer(GLenum mode);
+
+ void discardFramebuffer(GLenum target, GLsizei numAttachments, const GLenum *attachments);
+ void invalidateFramebuffer(GLenum target, GLsizei numAttachments, const GLenum *attachments);
+ void invalidateSubFramebuffer(GLenum target,
+ GLsizei numAttachments,
+ const GLenum *attachments,
+ GLint x,
+ GLint y,
+ GLsizei width,
+ GLsizei height);
+
Error flush();
Error finish();
- void recordError(const Error &error);
+ void insertEventMarker(GLsizei length, const char *marker);
+ void pushGroupMarker(GLsizei length, const char *marker);
+ void popGroupMarker();
+
+ void recordError(const Error &error) override;
GLenum getError();
GLenum getResetStatus();
virtual bool isResetNotificationEnabled();
- virtual int getClientVersion() const;
-
- EGLint getConfigID() const;
+ const egl::Config *getConfig() const;
EGLenum getClientType() const;
EGLenum getRenderBuffer() const;
- const Caps &getCaps() const;
- const TextureCapsMap &getTextureCaps() const;
- const Extensions &getExtensions() const;
-
const std::string &getRendererString() const;
const std::string &getExtensionString() const;
@@ -197,11 +312,15 @@ class Context final : angle::NonCopyable
rx::Renderer *getRenderer() { return mRenderer; }
State &getState() { return mState; }
- const State &getState() const { return mState; }
- Data getData() const;
+ void syncRendererState();
+ void syncRendererState(const State::DirtyBits &bitMask);
private:
+ void checkVertexArrayAllocation(GLuint vertexArray);
+ void checkTransformFeedbackAllocation(GLuint transformFeedback);
+ Framebuffer *checkFramebufferAllocation(GLuint framebufferHandle);
+
void detachBuffer(GLuint buffer);
void detachTexture(GLuint texture);
void detachFramebuffer(GLuint framebuffer);
@@ -219,6 +338,7 @@ class Context final : angle::NonCopyable
Caps mCaps;
TextureCapsMap mTextureCaps;
Extensions mExtensions;
+ Limitations mLimitations;
// Shader compiler
Compiler *mCompiler;
@@ -228,9 +348,8 @@ class Context final : angle::NonCopyable
int mClientVersion;
- EGLint mConfigID;
+ const egl::Config *mConfig;
EGLenum mClientType;
- EGLenum mRenderBuffer;
TextureMap mZeroTextures;
@@ -250,7 +369,6 @@ class Context final : angle::NonCopyable
VertexArrayMap mVertexArrayMap;
HandleAllocator mVertexArrayHandleAllocator;
- BindingPointer<TransformFeedback> mTransformFeedbackZero;
typedef std::map<GLuint, TransformFeedback*> TransformFeedbackMap;
TransformFeedbackMap mTransformFeedbackMap;
HandleAllocator mTransformFeedbackAllocator;
@@ -269,9 +387,11 @@ class Context final : angle::NonCopyable
GLenum mResetStatus;
GLenum mResetStrategy;
bool mRobustAccess;
+ egl::Surface *mCurrentSurface;
ResourceManager *mResourceManager;
};
-}
+
+} // namespace gl
#endif // LIBANGLE_CONTEXT_H_
diff --git a/src/3rdparty/angle/src/libANGLE/Data.cpp b/src/3rdparty/angle/src/libANGLE/Data.cpp
index 7832e21b23..83f04b5a0b 100644
--- a/src/3rdparty/angle/src/libANGLE/Data.cpp
+++ b/src/3rdparty/angle/src/libANGLE/Data.cpp
@@ -12,40 +12,45 @@
namespace gl
{
-Data::Data(GLint clientVersionIn, const State &stateIn, const Caps &capsIn,
- const TextureCapsMap &textureCapsIn, const Extensions &extensionsIn,
- const ResourceManager *resourceManagerIn)
- : clientVersion(clientVersionIn),
+Data::Data(uintptr_t contextIn,
+ GLint clientVersionIn,
+ const State &stateIn,
+ const Caps &capsIn,
+ const TextureCapsMap &textureCapsIn,
+ const Extensions &extensionsIn,
+ const ResourceManager *resourceManagerIn,
+ const Limitations &limitationsIn)
+ : context(contextIn),
+ clientVersion(clientVersionIn),
state(&stateIn),
caps(&capsIn),
textureCaps(&textureCapsIn),
extensions(&extensionsIn),
- resourceManager(resourceManagerIn)
+ resourceManager(resourceManagerIn),
+ limitations(&limitationsIn)
{}
Data::~Data()
{
}
-Data::Data(const Data &other)
- : clientVersion(other.clientVersion),
- state(other.state),
- caps(other.caps),
- textureCaps(other.textureCaps),
- extensions(other.extensions),
- resourceManager(other.resourceManager)
+ValidationContext::ValidationContext(GLint clientVersion,
+ const State &state,
+ const Caps &caps,
+ const TextureCapsMap &textureCaps,
+ const Extensions &extensions,
+ const ResourceManager *resourceManager,
+ const Limitations &limitations,
+ bool skipValidation)
+ : mData(reinterpret_cast<uintptr_t>(this),
+ clientVersion,
+ state,
+ caps,
+ textureCaps,
+ extensions,
+ resourceManager,
+ limitations),
+ mSkipValidation(skipValidation)
{
}
-
-Data &Data::operator=(const Data &other)
-{
- clientVersion = other.clientVersion;
- state = other.state;
- caps = other.caps;
- textureCaps = other.textureCaps;
- extensions = other.extensions;
- resourceManager = other.resourceManager;
- return *this;
-}
-
-}
+} // namespace gl
diff --git a/src/3rdparty/angle/src/libANGLE/Data.h b/src/3rdparty/angle/src/libANGLE/Data.h
index 7eb6827dfc..f7230d74bc 100644
--- a/src/3rdparty/angle/src/libANGLE/Data.h
+++ b/src/3rdparty/angle/src/libANGLE/Data.h
@@ -9,28 +9,62 @@
#ifndef LIBANGLE_DATA_H_
#define LIBANGLE_DATA_H_
+#include "common/angleutils.h"
#include "libANGLE/State.h"
namespace gl
{
-struct Data final
+struct Data final : public angle::NonCopyable
{
public:
- Data(GLint clientVersion, const State &state, const Caps &caps,
- const TextureCapsMap &textureCaps, const Extensions &extensions,
- const ResourceManager *resourceManager);
+ Data(uintptr_t context,
+ GLint clientVersion,
+ const State &state,
+ const Caps &caps,
+ const TextureCapsMap &textureCaps,
+ const Extensions &extensions,
+ const ResourceManager *resourceManager,
+ const Limitations &limitations);
~Data();
- Data(const Data &other);
- Data &operator=(const Data &other);
-
+ uintptr_t context;
GLint clientVersion;
const State *state;
const Caps *caps;
const TextureCapsMap *textureCaps;
const Extensions *extensions;
const ResourceManager *resourceManager;
+ const Limitations *limitations;
+};
+
+class ValidationContext : angle::NonCopyable
+{
+ public:
+ ValidationContext(GLint clientVersion,
+ const State &state,
+ const Caps &caps,
+ const TextureCapsMap &textureCaps,
+ const Extensions &extensions,
+ const ResourceManager *resourceManager,
+ const Limitations &limitations,
+ bool skipValidation);
+ virtual ~ValidationContext() {}
+
+ virtual void recordError(const Error &error) = 0;
+
+ const Data &getData() const { return mData; }
+ int getClientVersion() const { return mData.clientVersion; }
+ const State &getState() const { return *mData.state; }
+ const Caps &getCaps() const { return *mData.caps; }
+ const TextureCapsMap &getTextureCaps() const { return *mData.textureCaps; }
+ const Extensions &getExtensions() const { return *mData.extensions; }
+ const Limitations &getLimitations() const { return *mData.limitations; }
+ bool skipValidation() const { return mSkipValidation; }
+
+ protected:
+ Data mData;
+ bool mSkipValidation;
};
}
diff --git a/src/3rdparty/angle/src/libANGLE/Debug.cpp b/src/3rdparty/angle/src/libANGLE/Debug.cpp
new file mode 100644
index 0000000000..30321f4160
--- /dev/null
+++ b/src/3rdparty/angle/src/libANGLE/Debug.cpp
@@ -0,0 +1,303 @@
+//
+// 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.
+//
+
+// Debug.cpp: Defines debug state used for GL_KHR_debug
+
+#include "libANGLE/Debug.h"
+
+#include "common/debug.h"
+
+#include <algorithm>
+#include <tuple>
+
+namespace gl
+{
+
+Debug::Debug()
+ : mOutputEnabled(false),
+ mCallbackFunction(nullptr),
+ mCallbackUserParam(nullptr),
+ mMessages(),
+ mMaxLoggedMessages(0),
+ mOutputSynchronous(false),
+ mGroups()
+{
+ pushDefaultGroup();
+}
+
+void Debug::setMaxLoggedMessages(GLuint maxLoggedMessages)
+{
+ mMaxLoggedMessages = maxLoggedMessages;
+}
+
+void Debug::setOutputEnabled(bool enabled)
+{
+ mOutputEnabled = enabled;
+}
+
+bool Debug::isOutputEnabled() const
+{
+ return mOutputEnabled;
+}
+
+void Debug::setOutputSynchronous(bool synchronous)
+{
+ mOutputSynchronous = synchronous;
+}
+
+bool Debug::isOutputSynchronous() const
+{
+ return mOutputSynchronous;
+}
+
+void Debug::setCallback(GLDEBUGPROCKHR callback, const void *userParam)
+{
+ mCallbackFunction = callback;
+ mCallbackUserParam = userParam;
+}
+
+GLDEBUGPROCKHR Debug::getCallback() const
+{
+ return mCallbackFunction;
+}
+
+const void *Debug::getUserParam() const
+{
+ return mCallbackUserParam;
+}
+
+void Debug::insertMessage(GLenum source,
+ GLenum type,
+ GLuint id,
+ GLenum severity,
+ const std::string &message)
+{
+ std::string messageCopy(message);
+ insertMessage(source, type, id, severity, std::move(messageCopy));
+}
+
+void Debug::insertMessage(GLenum source,
+ GLenum type,
+ GLuint id,
+ GLenum severity,
+ std::string &&message)
+{
+ if (!isMessageEnabled(source, type, id, severity))
+ {
+ return;
+ }
+
+ if (mCallbackFunction != nullptr)
+ {
+ // TODO(geofflang) Check the synchronous flag and potentially flush messages from another
+ // thread.
+ mCallbackFunction(source, type, id, severity, static_cast<GLsizei>(message.length()),
+ message.c_str(), mCallbackUserParam);
+ }
+ else
+ {
+ if (mMessages.size() >= mMaxLoggedMessages)
+ {
+ // Drop messages over the limit
+ return;
+ }
+
+ Message m;
+ m.source = source;
+ m.type = type;
+ m.id = id;
+ m.severity = severity;
+ m.message = std::move(message);
+
+ mMessages.push_back(std::move(m));
+ }
+}
+
+size_t Debug::getMessages(GLuint count,
+ GLsizei bufSize,
+ GLenum *sources,
+ GLenum *types,
+ GLuint *ids,
+ GLenum *severities,
+ GLsizei *lengths,
+ GLchar *messageLog)
+{
+ size_t messageCount = 0;
+ size_t messageStringIndex = 0;
+ while (messageCount <= count && !mMessages.empty())
+ {
+ const Message &m = mMessages.front();
+
+ if (messageLog != nullptr)
+ {
+ // Check that this message can fit in the message buffer
+ if (messageStringIndex + m.message.length() + 1 > static_cast<size_t>(bufSize))
+ {
+ break;
+ }
+
+ std::copy(m.message.begin(), m.message.end(), messageLog + messageStringIndex);
+ messageStringIndex += m.message.length();
+
+ messageLog[messageStringIndex] = '\0';
+ messageStringIndex += 1;
+ }
+
+ if (sources != nullptr)
+ {
+ sources[messageCount] = m.source;
+ }
+
+ if (types != nullptr)
+ {
+ types[messageCount] = m.type;
+ }
+
+ if (ids != nullptr)
+ {
+ ids[messageCount] = m.id;
+ }
+
+ if (severities != nullptr)
+ {
+ severities[messageCount] = m.severity;
+ }
+
+ if (lengths != nullptr)
+ {
+ lengths[messageCount] = static_cast<GLsizei>(m.message.length());
+ }
+
+ mMessages.pop_front();
+
+ messageCount++;
+ }
+
+ return messageCount;
+}
+
+size_t Debug::getNextMessageLength() const
+{
+ return mMessages.empty() ? 0 : mMessages.front().message.length();
+}
+
+size_t Debug::getMessageCount() const
+{
+ return mMessages.size();
+}
+
+void Debug::setMessageControl(GLenum source,
+ GLenum type,
+ GLenum severity,
+ std::vector<GLuint> &&ids,
+ bool enabled)
+{
+ Control c;
+ c.source = source;
+ c.type = type;
+ c.severity = severity;
+ c.ids = std::move(ids);
+ c.enabled = enabled;
+
+ auto &controls = mGroups.back().controls;
+ controls.push_back(std::move(c));
+}
+
+void Debug::pushGroup(GLenum source, GLuint id, std::string &&message)
+{
+ insertMessage(source, GL_DEBUG_TYPE_PUSH_GROUP, id, GL_DEBUG_SEVERITY_NOTIFICATION,
+ std::string(message));
+
+ Group g;
+ g.source = source;
+ g.id = id;
+ g.message = std::move(message);
+ mGroups.push_back(std::move(g));
+}
+
+void Debug::popGroup()
+{
+ // Make sure the default group is not about to be popped
+ ASSERT(mGroups.size() > 1);
+
+ Group g = mGroups.back();
+ mGroups.pop_back();
+
+ insertMessage(g.source, GL_DEBUG_TYPE_POP_GROUP, g.id, GL_DEBUG_SEVERITY_NOTIFICATION,
+ g.message);
+}
+
+size_t Debug::getGroupStackDepth() const
+{
+ return mGroups.size();
+}
+
+bool Debug::isMessageEnabled(GLenum source, GLenum type, GLuint id, GLenum severity) const
+{
+ if (!mOutputEnabled)
+ {
+ return false;
+ }
+
+ for (auto groupIter = mGroups.rbegin(); groupIter != mGroups.rend(); groupIter++)
+ {
+ const auto &controls = groupIter->controls;
+ for (auto controlIter = controls.rbegin(); controlIter != controls.rend(); controlIter++)
+ {
+ const auto &control = *controlIter;
+
+ if (control.source != GL_DONT_CARE && control.source != source)
+ {
+ continue;
+ }
+
+ if (control.type != GL_DONT_CARE && control.type != type)
+ {
+ continue;
+ }
+
+ if (control.severity != GL_DONT_CARE && control.severity != severity)
+ {
+ continue;
+ }
+
+ if (!control.ids.empty() &&
+ std::find(control.ids.begin(), control.ids.end(), id) == control.ids.end())
+ {
+ continue;
+ }
+
+ return control.enabled;
+ }
+ }
+
+ return true;
+}
+
+void Debug::pushDefaultGroup()
+{
+ Group g;
+ g.source = GL_NONE;
+ g.id = 0;
+ g.message = "";
+
+ Control c0;
+ c0.source = GL_DONT_CARE;
+ c0.type = GL_DONT_CARE;
+ c0.severity = GL_DONT_CARE;
+ c0.enabled = true;
+ g.controls.push_back(std::move(c0));
+
+ Control c1;
+ c1.source = GL_DONT_CARE;
+ c1.type = GL_DONT_CARE;
+ c1.severity = GL_DEBUG_SEVERITY_LOW;
+ c1.enabled = false;
+ g.controls.push_back(std::move(c1));
+
+ mGroups.push_back(std::move(g));
+}
+} // namespace gl
diff --git a/src/3rdparty/angle/src/libANGLE/Debug.h b/src/3rdparty/angle/src/libANGLE/Debug.h
new file mode 100644
index 0000000000..f545b815e4
--- /dev/null
+++ b/src/3rdparty/angle/src/libANGLE/Debug.h
@@ -0,0 +1,120 @@
+//
+// 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.
+//
+
+// Debug.h: Defines debug state used for GL_KHR_debug
+
+#ifndef LIBANGLE_DEBUG_H_
+#define LIBANGLE_DEBUG_H_
+
+#include "angle_gl.h"
+#include "common/angleutils.h"
+
+#include <deque>
+#include <string>
+#include <vector>
+
+namespace gl
+{
+
+class LabeledObject
+{
+ public:
+ virtual ~LabeledObject() {}
+ virtual void setLabel(const std::string &label) = 0;
+ virtual const std::string &getLabel() const = 0;
+};
+
+class Debug : angle::NonCopyable
+{
+ public:
+ Debug();
+
+ void setMaxLoggedMessages(GLuint maxLoggedMessages);
+
+ void setOutputEnabled(bool enabled);
+ bool isOutputEnabled() const;
+
+ void setOutputSynchronous(bool synchronous);
+ bool isOutputSynchronous() const;
+
+ void setCallback(GLDEBUGPROCKHR callback, const void *userParam);
+ GLDEBUGPROCKHR getCallback() const;
+ const void *getUserParam() const;
+
+ void insertMessage(GLenum source,
+ GLenum type,
+ GLuint id,
+ GLenum severity,
+ const std::string &message);
+ void insertMessage(GLenum source,
+ GLenum type,
+ GLuint id,
+ GLenum severity,
+ std::string &&message);
+
+ void setMessageControl(GLenum source,
+ GLenum type,
+ GLenum severity,
+ std::vector<GLuint> &&ids,
+ bool enabled);
+ size_t getMessages(GLuint count,
+ GLsizei bufSize,
+ GLenum *sources,
+ GLenum *types,
+ GLuint *ids,
+ GLenum *severities,
+ GLsizei *lengths,
+ GLchar *messageLog);
+ size_t getNextMessageLength() const;
+ size_t getMessageCount() const;
+
+ void pushGroup(GLenum source, GLuint id, std::string &&message);
+ void popGroup();
+ size_t getGroupStackDepth() const;
+
+ private:
+ bool isMessageEnabled(GLenum source, GLenum type, GLuint id, GLenum severity) const;
+
+ void pushDefaultGroup();
+
+ struct Message
+ {
+ GLenum source;
+ GLenum type;
+ GLuint id;
+ GLenum severity;
+ std::string message;
+ };
+
+ struct Control
+ {
+ GLenum source;
+ GLenum type;
+ GLenum severity;
+ std::vector<GLuint> ids;
+ bool enabled;
+ };
+
+ struct Group
+ {
+ GLenum source;
+ GLuint id;
+ std::string message;
+
+ std::vector<Control> controls;
+ };
+
+ bool mOutputEnabled;
+ GLDEBUGPROCKHR mCallbackFunction;
+ const void *mCallbackUserParam;
+ std::deque<Message> mMessages;
+ GLuint mMaxLoggedMessages;
+ bool mOutputSynchronous;
+ std::vector<Group> mGroups;
+};
+} // namespace gl
+
+#endif // LIBANGLE_DEBUG_H_
diff --git a/src/3rdparty/angle/src/libANGLE/Debug2.cpp b/src/3rdparty/angle/src/libANGLE/Debug2.cpp
new file mode 100644
index 0000000000..30321f4160
--- /dev/null
+++ b/src/3rdparty/angle/src/libANGLE/Debug2.cpp
@@ -0,0 +1,303 @@
+//
+// 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.
+//
+
+// Debug.cpp: Defines debug state used for GL_KHR_debug
+
+#include "libANGLE/Debug.h"
+
+#include "common/debug.h"
+
+#include <algorithm>
+#include <tuple>
+
+namespace gl
+{
+
+Debug::Debug()
+ : mOutputEnabled(false),
+ mCallbackFunction(nullptr),
+ mCallbackUserParam(nullptr),
+ mMessages(),
+ mMaxLoggedMessages(0),
+ mOutputSynchronous(false),
+ mGroups()
+{
+ pushDefaultGroup();
+}
+
+void Debug::setMaxLoggedMessages(GLuint maxLoggedMessages)
+{
+ mMaxLoggedMessages = maxLoggedMessages;
+}
+
+void Debug::setOutputEnabled(bool enabled)
+{
+ mOutputEnabled = enabled;
+}
+
+bool Debug::isOutputEnabled() const
+{
+ return mOutputEnabled;
+}
+
+void Debug::setOutputSynchronous(bool synchronous)
+{
+ mOutputSynchronous = synchronous;
+}
+
+bool Debug::isOutputSynchronous() const
+{
+ return mOutputSynchronous;
+}
+
+void Debug::setCallback(GLDEBUGPROCKHR callback, const void *userParam)
+{
+ mCallbackFunction = callback;
+ mCallbackUserParam = userParam;
+}
+
+GLDEBUGPROCKHR Debug::getCallback() const
+{
+ return mCallbackFunction;
+}
+
+const void *Debug::getUserParam() const
+{
+ return mCallbackUserParam;
+}
+
+void Debug::insertMessage(GLenum source,
+ GLenum type,
+ GLuint id,
+ GLenum severity,
+ const std::string &message)
+{
+ std::string messageCopy(message);
+ insertMessage(source, type, id, severity, std::move(messageCopy));
+}
+
+void Debug::insertMessage(GLenum source,
+ GLenum type,
+ GLuint id,
+ GLenum severity,
+ std::string &&message)
+{
+ if (!isMessageEnabled(source, type, id, severity))
+ {
+ return;
+ }
+
+ if (mCallbackFunction != nullptr)
+ {
+ // TODO(geofflang) Check the synchronous flag and potentially flush messages from another
+ // thread.
+ mCallbackFunction(source, type, id, severity, static_cast<GLsizei>(message.length()),
+ message.c_str(), mCallbackUserParam);
+ }
+ else
+ {
+ if (mMessages.size() >= mMaxLoggedMessages)
+ {
+ // Drop messages over the limit
+ return;
+ }
+
+ Message m;
+ m.source = source;
+ m.type = type;
+ m.id = id;
+ m.severity = severity;
+ m.message = std::move(message);
+
+ mMessages.push_back(std::move(m));
+ }
+}
+
+size_t Debug::getMessages(GLuint count,
+ GLsizei bufSize,
+ GLenum *sources,
+ GLenum *types,
+ GLuint *ids,
+ GLenum *severities,
+ GLsizei *lengths,
+ GLchar *messageLog)
+{
+ size_t messageCount = 0;
+ size_t messageStringIndex = 0;
+ while (messageCount <= count && !mMessages.empty())
+ {
+ const Message &m = mMessages.front();
+
+ if (messageLog != nullptr)
+ {
+ // Check that this message can fit in the message buffer
+ if (messageStringIndex + m.message.length() + 1 > static_cast<size_t>(bufSize))
+ {
+ break;
+ }
+
+ std::copy(m.message.begin(), m.message.end(), messageLog + messageStringIndex);
+ messageStringIndex += m.message.length();
+
+ messageLog[messageStringIndex] = '\0';
+ messageStringIndex += 1;
+ }
+
+ if (sources != nullptr)
+ {
+ sources[messageCount] = m.source;
+ }
+
+ if (types != nullptr)
+ {
+ types[messageCount] = m.type;
+ }
+
+ if (ids != nullptr)
+ {
+ ids[messageCount] = m.id;
+ }
+
+ if (severities != nullptr)
+ {
+ severities[messageCount] = m.severity;
+ }
+
+ if (lengths != nullptr)
+ {
+ lengths[messageCount] = static_cast<GLsizei>(m.message.length());
+ }
+
+ mMessages.pop_front();
+
+ messageCount++;
+ }
+
+ return messageCount;
+}
+
+size_t Debug::getNextMessageLength() const
+{
+ return mMessages.empty() ? 0 : mMessages.front().message.length();
+}
+
+size_t Debug::getMessageCount() const
+{
+ return mMessages.size();
+}
+
+void Debug::setMessageControl(GLenum source,
+ GLenum type,
+ GLenum severity,
+ std::vector<GLuint> &&ids,
+ bool enabled)
+{
+ Control c;
+ c.source = source;
+ c.type = type;
+ c.severity = severity;
+ c.ids = std::move(ids);
+ c.enabled = enabled;
+
+ auto &controls = mGroups.back().controls;
+ controls.push_back(std::move(c));
+}
+
+void Debug::pushGroup(GLenum source, GLuint id, std::string &&message)
+{
+ insertMessage(source, GL_DEBUG_TYPE_PUSH_GROUP, id, GL_DEBUG_SEVERITY_NOTIFICATION,
+ std::string(message));
+
+ Group g;
+ g.source = source;
+ g.id = id;
+ g.message = std::move(message);
+ mGroups.push_back(std::move(g));
+}
+
+void Debug::popGroup()
+{
+ // Make sure the default group is not about to be popped
+ ASSERT(mGroups.size() > 1);
+
+ Group g = mGroups.back();
+ mGroups.pop_back();
+
+ insertMessage(g.source, GL_DEBUG_TYPE_POP_GROUP, g.id, GL_DEBUG_SEVERITY_NOTIFICATION,
+ g.message);
+}
+
+size_t Debug::getGroupStackDepth() const
+{
+ return mGroups.size();
+}
+
+bool Debug::isMessageEnabled(GLenum source, GLenum type, GLuint id, GLenum severity) const
+{
+ if (!mOutputEnabled)
+ {
+ return false;
+ }
+
+ for (auto groupIter = mGroups.rbegin(); groupIter != mGroups.rend(); groupIter++)
+ {
+ const auto &controls = groupIter->controls;
+ for (auto controlIter = controls.rbegin(); controlIter != controls.rend(); controlIter++)
+ {
+ const auto &control = *controlIter;
+
+ if (control.source != GL_DONT_CARE && control.source != source)
+ {
+ continue;
+ }
+
+ if (control.type != GL_DONT_CARE && control.type != type)
+ {
+ continue;
+ }
+
+ if (control.severity != GL_DONT_CARE && control.severity != severity)
+ {
+ continue;
+ }
+
+ if (!control.ids.empty() &&
+ std::find(control.ids.begin(), control.ids.end(), id) == control.ids.end())
+ {
+ continue;
+ }
+
+ return control.enabled;
+ }
+ }
+
+ return true;
+}
+
+void Debug::pushDefaultGroup()
+{
+ Group g;
+ g.source = GL_NONE;
+ g.id = 0;
+ g.message = "";
+
+ Control c0;
+ c0.source = GL_DONT_CARE;
+ c0.type = GL_DONT_CARE;
+ c0.severity = GL_DONT_CARE;
+ c0.enabled = true;
+ g.controls.push_back(std::move(c0));
+
+ Control c1;
+ c1.source = GL_DONT_CARE;
+ c1.type = GL_DONT_CARE;
+ c1.severity = GL_DEBUG_SEVERITY_LOW;
+ c1.enabled = false;
+ g.controls.push_back(std::move(c1));
+
+ mGroups.push_back(std::move(g));
+}
+} // namespace gl
diff --git a/src/3rdparty/angle/src/libANGLE/Debug2.h b/src/3rdparty/angle/src/libANGLE/Debug2.h
new file mode 100644
index 0000000000..f545b815e4
--- /dev/null
+++ b/src/3rdparty/angle/src/libANGLE/Debug2.h
@@ -0,0 +1,120 @@
+//
+// 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.
+//
+
+// Debug.h: Defines debug state used for GL_KHR_debug
+
+#ifndef LIBANGLE_DEBUG_H_
+#define LIBANGLE_DEBUG_H_
+
+#include "angle_gl.h"
+#include "common/angleutils.h"
+
+#include <deque>
+#include <string>
+#include <vector>
+
+namespace gl
+{
+
+class LabeledObject
+{
+ public:
+ virtual ~LabeledObject() {}
+ virtual void setLabel(const std::string &label) = 0;
+ virtual const std::string &getLabel() const = 0;
+};
+
+class Debug : angle::NonCopyable
+{
+ public:
+ Debug();
+
+ void setMaxLoggedMessages(GLuint maxLoggedMessages);
+
+ void setOutputEnabled(bool enabled);
+ bool isOutputEnabled() const;
+
+ void setOutputSynchronous(bool synchronous);
+ bool isOutputSynchronous() const;
+
+ void setCallback(GLDEBUGPROCKHR callback, const void *userParam);
+ GLDEBUGPROCKHR getCallback() const;
+ const void *getUserParam() const;
+
+ void insertMessage(GLenum source,
+ GLenum type,
+ GLuint id,
+ GLenum severity,
+ const std::string &message);
+ void insertMessage(GLenum source,
+ GLenum type,
+ GLuint id,
+ GLenum severity,
+ std::string &&message);
+
+ void setMessageControl(GLenum source,
+ GLenum type,
+ GLenum severity,
+ std::vector<GLuint> &&ids,
+ bool enabled);
+ size_t getMessages(GLuint count,
+ GLsizei bufSize,
+ GLenum *sources,
+ GLenum *types,
+ GLuint *ids,
+ GLenum *severities,
+ GLsizei *lengths,
+ GLchar *messageLog);
+ size_t getNextMessageLength() const;
+ size_t getMessageCount() const;
+
+ void pushGroup(GLenum source, GLuint id, std::string &&message);
+ void popGroup();
+ size_t getGroupStackDepth() const;
+
+ private:
+ bool isMessageEnabled(GLenum source, GLenum type, GLuint id, GLenum severity) const;
+
+ void pushDefaultGroup();
+
+ struct Message
+ {
+ GLenum source;
+ GLenum type;
+ GLuint id;
+ GLenum severity;
+ std::string message;
+ };
+
+ struct Control
+ {
+ GLenum source;
+ GLenum type;
+ GLenum severity;
+ std::vector<GLuint> ids;
+ bool enabled;
+ };
+
+ struct Group
+ {
+ GLenum source;
+ GLuint id;
+ std::string message;
+
+ std::vector<Control> controls;
+ };
+
+ bool mOutputEnabled;
+ GLDEBUGPROCKHR mCallbackFunction;
+ const void *mCallbackUserParam;
+ std::deque<Message> mMessages;
+ GLuint mMaxLoggedMessages;
+ bool mOutputSynchronous;
+ std::vector<Group> mGroups;
+};
+} // namespace gl
+
+#endif // LIBANGLE_DEBUG_H_
diff --git a/src/3rdparty/angle/src/libANGLE/Device.cpp b/src/3rdparty/angle/src/libANGLE/Device.cpp
new file mode 100644
index 0000000000..eb30b2023f
--- /dev/null
+++ b/src/3rdparty/angle/src/libANGLE/Device.cpp
@@ -0,0 +1,130 @@
+//
+// 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.
+//
+
+// Device.cpp: Implements the egl::Device class, representing the abstract
+// device. Implements EGLDevice.
+
+#include "libANGLE/Device.h"
+
+#include <iterator>
+
+#include <platform/Platform.h>
+#include <EGL/eglext.h>
+
+#include "common/debug.h"
+#include "common/platform.h"
+#include "libANGLE/renderer/DeviceImpl.h"
+
+#if defined(ANGLE_ENABLE_D3D11)
+#include "libANGLE/renderer/d3d/DeviceD3D.h"
+#endif
+
+namespace egl
+{
+
+template <typename T>
+static std::string GenerateExtensionsString(const T &extensions)
+{
+ std::vector<std::string> extensionsVector = extensions.getStrings();
+
+ std::ostringstream stream;
+ std::copy(extensionsVector.begin(), extensionsVector.end(), std::ostream_iterator<std::string>(stream, " "));
+ return stream.str();
+}
+
+typedef std::set<egl::Device *> DeviceSet;
+static DeviceSet *GetDeviceSet()
+{
+ static DeviceSet devices;
+ return &devices;
+}
+
+// Static factory methods
+egl::Error Device::CreateDevice(void *devicePointer, EGLint deviceType, Device **outDevice)
+{
+#if defined(ANGLE_ENABLE_D3D11)
+ if (deviceType == EGL_D3D11_DEVICE_ANGLE)
+ {
+ rx::DeviceD3D *deviceD3D = new rx::DeviceD3D();
+ egl::Error error = deviceD3D->initialize(devicePointer, deviceType, EGL_TRUE);
+ if (error.isError())
+ {
+ *outDevice = nullptr;
+ return error;
+ }
+
+ *outDevice = new Device(nullptr, deviceD3D);
+ GetDeviceSet()->insert(*outDevice);
+ return egl::Error(EGL_SUCCESS);
+ }
+#endif
+
+ // Note that creating an EGL device from inputted D3D9 parameters isn't currently supported
+ *outDevice = nullptr;
+ return egl::Error(EGL_BAD_ATTRIBUTE);
+}
+
+egl::Error Device::CreateDevice(Display *owningDisplay, rx::DeviceImpl *impl, Device **outDevice)
+{
+ *outDevice = new Device(owningDisplay, impl);
+ GetDeviceSet()->insert(*outDevice);
+ return egl::Error(EGL_SUCCESS);
+}
+
+bool Device::IsValidDevice(Device *device)
+{
+ const DeviceSet *deviceSet = GetDeviceSet();
+ return deviceSet->find(device) != deviceSet->end();
+}
+
+Device::Device(Display *owningDisplay, rx::DeviceImpl *impl)
+ : mOwningDisplay(owningDisplay), mImplementation(impl)
+{
+ initDeviceExtensions();
+}
+
+Device::~Device()
+{
+ ASSERT(GetDeviceSet()->find(this) != GetDeviceSet()->end());
+ GetDeviceSet()->erase(this);
+
+ if (mImplementation->deviceExternallySourced())
+ {
+ // If the device isn't externally sourced then it is up to the renderer to delete the impl
+ SafeDelete(mImplementation);
+ }
+}
+
+Error Device::getDevice(EGLAttrib *value)
+{
+ void *nativeDevice = nullptr;
+ egl::Error error = getImplementation()->getDevice(&nativeDevice);
+ *value = reinterpret_cast<EGLAttrib>(nativeDevice);
+ return error;
+}
+
+EGLint Device::getType()
+{
+ return getImplementation()->getType();
+}
+
+void Device::initDeviceExtensions()
+{
+ mImplementation->generateExtensions(&mDeviceExtensions);
+ mDeviceExtensionString = GenerateExtensionsString(mDeviceExtensions);
+}
+
+const DeviceExtensions &Device::getExtensions() const
+{
+ return mDeviceExtensions;
+}
+
+const std::string &Device::getExtensionString() const
+{
+ return mDeviceExtensionString;
+}
+
+}
diff --git a/src/3rdparty/angle/src/libANGLE/Device.h b/src/3rdparty/angle/src/libANGLE/Device.h
new file mode 100644
index 0000000000..4bc58ff043
--- /dev/null
+++ b/src/3rdparty/angle/src/libANGLE/Device.h
@@ -0,0 +1,58 @@
+//
+// 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.
+//
+
+// Device.h: Implements the egl::Device class, representing the abstract
+// device. Implements EGLDevice.
+
+#ifndef LIBANGLE_DEVICE_H_
+#define LIBANGLE_DEVICE_H_
+
+#include "common/angleutils.h"
+#include "libANGLE/Error.h"
+#include "libANGLE/Display.h"
+
+namespace rx
+{
+class DeviceImpl;
+}
+
+namespace egl
+{
+class Device final : angle::NonCopyable
+{
+ public:
+ virtual ~Device();
+
+ Error getDevice(EGLAttrib *value);
+ Display *getOwningDisplay() { return mOwningDisplay; };
+ EGLint getType();
+
+ const DeviceExtensions &getExtensions() const;
+ const std::string &getExtensionString() const;
+
+ rx::DeviceImpl *getImplementation() { return mImplementation; }
+
+ static egl::Error CreateDevice(void *devicePointer, EGLint deviceType, Device **outDevice);
+ static egl::Error CreateDevice(Display *owningDisplay,
+ rx::DeviceImpl *impl,
+ Device **outDevice);
+
+ static bool IsValidDevice(Device *device);
+
+ private:
+ Device(Display *owningDisplay, rx::DeviceImpl *impl);
+ void initDeviceExtensions();
+
+ Display *mOwningDisplay;
+ rx::DeviceImpl *mImplementation;
+
+ DeviceExtensions mDeviceExtensions;
+ std::string mDeviceExtensionString;
+};
+
+}
+
+#endif // LIBANGLE_DEVICE_H_
diff --git a/src/3rdparty/angle/src/libANGLE/Display.cpp b/src/3rdparty/angle/src/libANGLE/Display.cpp
index 1f54f82dea..486c74abc0 100644
--- a/src/3rdparty/angle/src/libANGLE/Display.cpp
+++ b/src/3rdparty/angle/src/libANGLE/Display.cpp
@@ -22,9 +22,15 @@
#include "common/debug.h"
#include "common/mathutil.h"
#include "common/platform.h"
+#include "common/utilities.h"
#include "libANGLE/Context.h"
+#include "libANGLE/Device.h"
+#include "libANGLE/histogram_macros.h"
+#include "libANGLE/Image.h"
#include "libANGLE/Surface.h"
#include "libANGLE/renderer/DisplayImpl.h"
+#include "libANGLE/renderer/ImageImpl.h"
+#include "third_party/trace_event/trace_event.h"
#if defined(ANGLE_ENABLE_D3D9) || defined(ANGLE_ENABLE_D3D11)
# include "libANGLE/renderer/d3d/DisplayD3D.h"
@@ -33,6 +39,10 @@
#if defined(ANGLE_ENABLE_OPENGL)
# if defined(ANGLE_PLATFORM_WINDOWS)
# include "libANGLE/renderer/gl/wgl/DisplayWGL.h"
+# elif defined(ANGLE_USE_X11)
+# include "libANGLE/renderer/gl/glx/DisplayGLX.h"
+# elif defined(ANGLE_PLATFORM_APPLE)
+# include "libANGLE/renderer/gl/cgl/DisplayCGL.h"
# else
# error Unsupported OpenGL platform.
# endif
@@ -66,19 +76,6 @@ void InitDefaultPlatformImpl()
}
}
-void DeinitDefaultPlatformImpl()
-{
- if (defaultPlatform != nullptr)
- {
- if (ANGLEPlatformCurrent() == defaultPlatform)
- {
- ANGLEPlatformShutdown();
- }
-
- SafeDelete(defaultPlatform);
- }
-}
-
typedef std::map<EGLNativeWindowType, Surface*> WindowSurfaceMap;
// Get a map of all EGL window surfaces to validate that no window has more than one EGL surface
// associated with it.
@@ -88,14 +85,52 @@ static WindowSurfaceMap *GetWindowSurfaces()
return &windowSurfaces;
}
-typedef std::map<EGLNativeDisplayType, Display*> DisplayMap;
-static DisplayMap *GetDisplayMap()
+typedef std::map<EGLNativeDisplayType, Display *> ANGLEPlatformDisplayMap;
+static ANGLEPlatformDisplayMap *GetANGLEPlatformDisplayMap()
+{
+ static ANGLEPlatformDisplayMap displays;
+ return &displays;
+}
+
+typedef std::map<Device *, Display *> DevicePlatformDisplayMap;
+static DevicePlatformDisplayMap *GetDevicePlatformDisplayMap()
{
- static DisplayMap displays;
+ static DevicePlatformDisplayMap displays;
return &displays;
}
-rx::DisplayImpl *CreateDisplayImpl(const AttributeMap &attribMap)
+rx::DisplayImpl *CreateDisplayFromDevice(Device *eglDevice)
+{
+ rx::DisplayImpl *impl = nullptr;
+
+ switch (eglDevice->getType())
+ {
+#if defined(ANGLE_ENABLE_D3D11)
+ case EGL_D3D11_DEVICE_ANGLE:
+ impl = new rx::DisplayD3D();
+ break;
+#endif
+#if defined(ANGLE_ENABLE_D3D9)
+ case EGL_D3D9_DEVICE_ANGLE:
+ // Currently the only way to get EGLDeviceEXT representing a D3D9 device
+ // is to retrieve one from an already-existing EGLDisplay.
+ // When eglGetPlatformDisplayEXT is called with a D3D9 EGLDeviceEXT,
+ // the already-existing display should be returned.
+ // Therefore this codepath to create a new display from the device
+ // should never be hit.
+ UNREACHABLE();
+ break;
+#endif
+ default:
+ UNREACHABLE();
+ break;
+ }
+
+ ASSERT(impl != nullptr);
+ return impl;
+}
+
+rx::DisplayImpl *CreateDisplayFromAttribs(const AttributeMap &attribMap)
{
rx::DisplayImpl *impl = nullptr;
EGLint displayType = attribMap.get(EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE);
@@ -105,6 +140,10 @@ rx::DisplayImpl *CreateDisplayImpl(const AttributeMap &attribMap)
#if defined(ANGLE_ENABLE_D3D9) || defined(ANGLE_ENABLE_D3D11)
// Default to D3D displays
impl = new rx::DisplayD3D();
+#elif defined(ANGLE_USE_X11)
+ impl = new rx::DisplayGLX();
+#elif defined(ANGLE_PLATFORM_APPLE)
+ impl = new rx::DisplayCGL();
#else
// No display available
UNREACHABLE();
@@ -125,6 +164,10 @@ rx::DisplayImpl *CreateDisplayImpl(const AttributeMap &attribMap)
#if defined(ANGLE_ENABLE_OPENGL)
#if defined(ANGLE_PLATFORM_WINDOWS)
impl = new rx::DisplayWGL();
+#elif defined(ANGLE_USE_X11)
+ impl = new rx::DisplayGLX();
+#elif defined(ANGLE_PLATFORM_APPLE)
+ impl = new rx::DisplayCGL();
#else
#error Unsupported OpenGL platform.
#endif
@@ -133,26 +176,40 @@ rx::DisplayImpl *CreateDisplayImpl(const AttributeMap &attribMap)
#endif
break;
+#if defined(ANGLE_ENABLE_OPENGL)
+ case EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE:
+#if defined(ANGLE_PLATFORM_WINDOWS)
+ impl = new rx::DisplayWGL();
+#elif defined(ANGLE_USE_X11)
+ impl = new rx::DisplayGLX();
+#else
+ // No GLES support on this platform, fail display creation.
+ impl = nullptr;
+#endif
+ break;
+#endif
+
default:
UNREACHABLE();
break;
}
- ASSERT(impl != nullptr);
return impl;
}
}
-Display *Display::getDisplay(EGLNativeDisplayType displayId, const AttributeMap &attribMap)
+Display *Display::GetDisplayFromAttribs(void *native_display, const AttributeMap &attribMap)
{
// Initialize the global platform if not already
InitDefaultPlatformImpl();
- Display *display = NULL;
+ Display *display = nullptr;
+
+ EGLNativeDisplayType displayId = reinterpret_cast<EGLNativeDisplayType>(native_display);
- DisplayMap *displays = GetDisplayMap();
- DisplayMap::const_iterator iter = displays->find(displayId);
+ ANGLEPlatformDisplayMap *displays = GetANGLEPlatformDisplayMap();
+ ANGLEPlatformDisplayMap::const_iterator iter = displays->find(displayId);
if (iter != displays->end())
{
display = iter->second;
@@ -166,21 +223,77 @@ Display *Display::getDisplay(EGLNativeDisplayType displayId, const AttributeMap
return NULL;
}
- display = new Display(displayId);
+ display = new Display(EGL_PLATFORM_ANGLE_ANGLE, displayId, nullptr);
displays->insert(std::make_pair(displayId, display));
}
// Apply new attributes if the display is not initialized yet.
if (!display->isInitialized())
{
- rx::DisplayImpl* impl = CreateDisplayImpl(attribMap);
+ rx::DisplayImpl *impl = CreateDisplayFromAttribs(attribMap);
+ if (impl == nullptr)
+ {
+ // No valid display implementation for these attributes
+ return nullptr;
+ }
+
display->setAttributes(impl, attribMap);
}
return display;
}
-Display::Display(EGLNativeDisplayType displayId)
+Display *Display::GetDisplayFromDevice(void *native_display)
+{
+ // Initialize the global platform if not already
+ InitDefaultPlatformImpl();
+
+ Display *display = nullptr;
+
+ Device *eglDevice = reinterpret_cast<Device *>(native_display);
+ ASSERT(Device::IsValidDevice(eglDevice));
+
+ ANGLEPlatformDisplayMap *anglePlatformDisplays = GetANGLEPlatformDisplayMap();
+ DevicePlatformDisplayMap *devicePlatformDisplays = GetDevicePlatformDisplayMap();
+
+ // First see if this eglDevice is in use by a Display created using ANGLE platform
+ for (auto &displayMapEntry : *anglePlatformDisplays)
+ {
+ egl::Display *iterDisplay = displayMapEntry.second;
+ if (iterDisplay->getDevice() == eglDevice)
+ {
+ display = iterDisplay;
+ }
+ }
+
+ if (display == nullptr)
+ {
+ // See if the eglDevice is in use by a Display created using the DEVICE platform
+ DevicePlatformDisplayMap::const_iterator iter = devicePlatformDisplays->find(eglDevice);
+ if (iter != devicePlatformDisplays->end())
+ {
+ display = iter->second;
+ }
+ }
+
+ if (display == nullptr)
+ {
+ // Otherwise create a new Display
+ display = new Display(EGL_PLATFORM_DEVICE_EXT, 0, eglDevice);
+ devicePlatformDisplays->insert(std::make_pair(eglDevice, display));
+ }
+
+ // Apply new attributes if the display is not initialized yet.
+ if (!display->isInitialized())
+ {
+ rx::DisplayImpl *impl = CreateDisplayFromDevice(eglDevice);
+ display->setAttributes(impl, egl::AttributeMap());
+ }
+
+ return display;
+}
+
+Display::Display(EGLenum platform, EGLNativeDisplayType displayId, Device *eglDevice)
: mImplementation(nullptr),
mDisplayId(displayId),
mAttributeMap(),
@@ -190,7 +303,9 @@ Display::Display(EGLNativeDisplayType displayId)
mCaps(),
mDisplayExtensions(),
mDisplayExtensionString(),
- mVendorString()
+ mVendorString(),
+ mDevice(eglDevice),
+ mPlatform(platform)
{
}
@@ -198,13 +313,30 @@ Display::~Display()
{
terminate();
- DisplayMap *displays = GetDisplayMap();
- DisplayMap::iterator iter = displays->find(mDisplayId);
- if (iter != displays->end())
+ if (mPlatform == EGL_PLATFORM_ANGLE_ANGLE)
+ {
+ ANGLEPlatformDisplayMap *displays = GetANGLEPlatformDisplayMap();
+ ANGLEPlatformDisplayMap::iterator iter = displays->find(mDisplayId);
+ if (iter != displays->end())
+ {
+ displays->erase(iter);
+ }
+ }
+ else if (mPlatform == EGL_PLATFORM_DEVICE_EXT)
+ {
+ DevicePlatformDisplayMap *displays = GetDevicePlatformDisplayMap();
+ DevicePlatformDisplayMap::iterator iter = displays->find(mDevice);
+ if (iter != displays->end())
+ {
+ displays->erase(iter);
+ }
+ }
+ else
{
- displays->erase(iter);
+ UNREACHABLE();
}
+ SafeDelete(mDevice);
SafeDelete(mImplementation);
}
@@ -221,6 +353,12 @@ void Display::setAttributes(rx::DisplayImpl *impl, const AttributeMap &attribMap
Error Display::initialize()
{
+ // Re-initialize default platform if it's needed
+ InitDefaultPlatformImpl();
+
+ SCOPED_ANGLE_HISTOGRAM_TIMER("GPU.ANGLE.DisplayInitializeMS");
+ TRACE_EVENT0("gpu.angle", "egl::Display::initialize");
+
ASSERT(mImplementation != nullptr);
if (isInitialized())
@@ -231,6 +369,11 @@ Error Display::initialize()
Error error = mImplementation->initialize(this);
if (error.isError())
{
+ // Log extended error message here
+ std::stringstream errorStream;
+ errorStream << "ANGLE Display::initialize error " << error.getID() << ": "
+ << error.getMessage();
+ ANGLEPlatformCurrent()->logError(errorStream.str().c_str());
return error;
}
@@ -246,7 +389,38 @@ Error Display::initialize()
initDisplayExtensions();
initVendorString();
+ // Populate the Display's EGLDeviceEXT if the Display wasn't created using one
+ if (mPlatform != EGL_PLATFORM_DEVICE_EXT)
+ {
+ if (mDisplayExtensions.deviceQuery)
+ {
+ rx::DeviceImpl *impl = nullptr;
+ error = mImplementation->getDevice(&impl);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ error = Device::CreateDevice(this, impl, &mDevice);
+ if (error.isError())
+ {
+ return error;
+ }
+ }
+ else
+ {
+ mDevice = nullptr;
+ }
+ }
+ else
+ {
+ // For EGL_PLATFORM_DEVICE_EXT, mDevice should always be populated using
+ // an external device
+ ASSERT(mDevice != nullptr);
+ }
+
mInitialized = true;
+
return Error(EGL_SUCCESS);
}
@@ -259,13 +433,30 @@ void Display::terminate()
destroyContext(*mContextSet.begin());
}
+ while (!mImageSet.empty())
+ {
+ destroyImage(*mImageSet.begin());
+ }
+
+ while (!mImplementation->getSurfaceSet().empty())
+ {
+ destroySurface(*mImplementation->getSurfaceSet().begin());
+ }
+
mConfigSet.clear();
+ if (mDevice != nullptr && mDevice->getOwningDisplay() != nullptr)
+ {
+ // Don't delete the device if it was created externally using eglCreateDeviceANGLE
+ // We also shouldn't set it to null in case eglInitialize() is called again later
+ SafeDelete(mDevice);
+ }
+
mImplementation->terminate();
+
mInitialized = false;
- // De-init default platform
- DeinitDefaultPlatformImpl();
+ // Never de-init default platform.. terminate is not that final.
}
std::vector<const Config*> Display::getConfigs(const egl::AttributeMap &attribs) const
@@ -288,6 +479,7 @@ bool Display::getConfigAttrib(const Config *configuration, EGLint attribute, EGL
case EGL_CONFIG_ID: *value = configuration->configID; break;
case EGL_LEVEL: *value = configuration->level; break;
case EGL_NATIVE_RENDERABLE: *value = configuration->nativeRenderable; break;
+ case EGL_NATIVE_VISUAL_ID: *value = configuration->nativeVisualID; break;
case EGL_NATIVE_VISUAL_TYPE: *value = configuration->nativeVisualType; break;
case EGL_SAMPLES: *value = configuration->samples; break;
case EGL_SAMPLE_BUFFERS: *value = configuration->sampleBuffers; break;
@@ -309,6 +501,15 @@ bool Display::getConfigAttrib(const Config *configuration, EGLint attribute, EGL
case EGL_MAX_PBUFFER_WIDTH: *value = configuration->maxPBufferWidth; break;
case EGL_MAX_PBUFFER_HEIGHT: *value = configuration->maxPBufferHeight; break;
case EGL_MAX_PBUFFER_PIXELS: *value = configuration->maxPBufferPixels; break;
+
+ case EGL_OPTIMAL_SURFACE_ORIENTATION_ANGLE:
+ if (!getExtensions().surfaceOrientation)
+ {
+ return false;
+ }
+ *value = configuration->optimalOrientation;
+ break;
+
default:
return false;
}
@@ -328,14 +529,16 @@ Error Display::createWindowSurface(const Config *configuration, EGLNativeWindowT
}
}
- rx::SurfaceImpl *surfaceImpl = nullptr;
- Error error = mImplementation->createWindowSurface(configuration, window, attribs, &surfaceImpl);
+ rx::SurfaceImpl *surfaceImpl = mImplementation->createWindowSurface(configuration, window, attribs);
+ ASSERT(surfaceImpl != nullptr);
+
+ Error error = surfaceImpl->initialize();
if (error.isError())
{
+ SafeDelete(surfaceImpl);
return error;
}
- ASSERT(surfaceImpl != nullptr);
Surface *surface = new Surface(surfaceImpl, EGL_WINDOW_BIT, configuration, attribs);
mImplementation->getSurfaceSet().insert(surface);
@@ -361,14 +564,16 @@ Error Display::createPbufferSurface(const Config *configuration, const Attribute
}
}
- rx::SurfaceImpl *surfaceImpl = nullptr;
- Error error = mImplementation->createPbufferSurface(configuration, attribs, &surfaceImpl);
+ rx::SurfaceImpl *surfaceImpl = mImplementation->createPbufferSurface(configuration, attribs);
+ ASSERT(surfaceImpl != nullptr);
+
+ Error error = surfaceImpl->initialize();
if (error.isError())
{
+ SafeDelete(surfaceImpl);
return error;
}
- ASSERT(surfaceImpl != nullptr);
Surface *surface = new Surface(surfaceImpl, EGL_PBUFFER_BIT, configuration, attribs);
mImplementation->getSurfaceSet().insert(surface);
@@ -391,14 +596,16 @@ Error Display::createPbufferFromClientBuffer(const Config *configuration, EGLCli
}
}
- rx::SurfaceImpl *surfaceImpl = nullptr;
- Error error = mImplementation->createPbufferFromClientBuffer(configuration, shareHandle, attribs, &surfaceImpl);
+ rx::SurfaceImpl *surfaceImpl = mImplementation->createPbufferFromClientBuffer(configuration, shareHandle, attribs);
+ ASSERT(surfaceImpl != nullptr);
+
+ Error error = surfaceImpl->initialize();
if (error.isError())
{
+ SafeDelete(surfaceImpl);
return error;
}
- ASSERT(surfaceImpl != nullptr);
Surface *surface = new Surface(surfaceImpl, EGL_PBUFFER_BIT, configuration, attribs);
mImplementation->getSurfaceSet().insert(surface);
@@ -421,14 +628,16 @@ Error Display::createPixmapSurface(const Config *configuration, NativePixmapType
}
}
- rx::SurfaceImpl *surfaceImpl = nullptr;
- Error error = mImplementation->createPixmapSurface(configuration, nativePixmap, attribs, &surfaceImpl);
+ rx::SurfaceImpl *surfaceImpl = mImplementation->createPixmapSurface(configuration, nativePixmap, attribs);
+ ASSERT(surfaceImpl != nullptr);
+
+ Error error = surfaceImpl->initialize();
if (error.isError())
{
+ SafeDelete(surfaceImpl);
return error;
}
- ASSERT(surfaceImpl != nullptr);
Surface *surface = new Surface(surfaceImpl, EGL_PIXMAP_BIT, configuration, attribs);
mImplementation->getSurfaceSet().insert(surface);
@@ -437,8 +646,11 @@ Error Display::createPixmapSurface(const Config *configuration, NativePixmapType
return Error(EGL_SUCCESS);
}
-Error Display::createContext(const Config *configuration, gl::Context *shareContext, const AttributeMap &attribs,
- gl::Context **outContext)
+Error Display::createImage(gl::Context *context,
+ EGLenum target,
+ EGLClientBuffer buffer,
+ const AttributeMap &attribs,
+ Image **outImage)
{
ASSERT(isInitialized());
@@ -451,13 +663,59 @@ Error Display::createContext(const Config *configuration, gl::Context *shareCont
}
}
- gl::Context *context = nullptr;
- Error error = mImplementation->createContext(configuration, shareContext, attribs, &context);
+ egl::ImageSibling *sibling = nullptr;
+ if (IsTextureTarget(target))
+ {
+ sibling = context->getTexture(egl_gl::EGLClientBufferToGLObjectHandle(buffer));
+ }
+ else if (IsRenderbufferTarget(target))
+ {
+ sibling = context->getRenderbuffer(egl_gl::EGLClientBufferToGLObjectHandle(buffer));
+ }
+ else
+ {
+ UNREACHABLE();
+ }
+ ASSERT(sibling != nullptr);
+
+ rx::ImageImpl *imageImpl = mImplementation->createImage(target, sibling, attribs);
+ ASSERT(imageImpl != nullptr);
+
+ Error error = imageImpl->initialize();
if (error.isError())
{
return error;
}
+ Image *image = new Image(imageImpl, target, sibling, attribs);
+
+ ASSERT(outImage != nullptr);
+ *outImage = image;
+
+ // Add this image to the list of all images and hold a ref to it.
+ image->addRef();
+ mImageSet.insert(image);
+
+ return Error(EGL_SUCCESS);
+}
+
+Error Display::createContext(const Config *configuration, gl::Context *shareContext, const AttributeMap &attribs,
+ gl::Context **outContext)
+{
+ ASSERT(isInitialized());
+
+ if (mImplementation->testDeviceLost())
+ {
+ Error error = restoreLostDevice();
+ if (error.isError())
+ {
+ return error;
+ }
+ }
+
+ gl::Context *context = *outContext =
+ mImplementation->createContext(configuration, shareContext, attribs);
+
ASSERT(context != nullptr);
mContextSet.insert(context);
@@ -474,8 +732,9 @@ Error Display::makeCurrent(egl::Surface *drawSurface, egl::Surface *readSurface,
return error;
}
- if (context && drawSurface)
+ if (context != nullptr && drawSurface != nullptr)
{
+ ASSERT(readSurface == drawSurface);
context->makeCurrent(drawSurface);
}
@@ -515,11 +774,20 @@ void Display::destroySurface(Surface *surface)
}
ASSERT(surfaceRemoved);
+ UNUSED_ASSERTION_VARIABLE(surfaceRemoved);
}
mImplementation->destroySurface(surface);
}
+void Display::destroyImage(egl::Image *image)
+{
+ auto iter = mImageSet.find(image);
+ ASSERT(iter != mImageSet.end());
+ (*iter)->release();
+ mImageSet.erase(iter);
+}
+
void Display::destroyContext(gl::Context *context)
{
mContextSet.erase(context);
@@ -546,6 +814,16 @@ void Display::notifyDeviceLost()
}
}
+Error Display::waitClient() const
+{
+ return mImplementation->waitClient();
+}
+
+Error Display::waitNative(EGLint engine, egl::Surface *drawSurface, egl::Surface *readSurface) const
+{
+ return mImplementation->waitNative(engine, drawSurface, readSurface);
+}
+
const Caps &Display::getCaps() const
{
return mCaps;
@@ -571,6 +849,11 @@ bool Display::isValidSurface(Surface *surface) const
return mImplementation->getSurfaceSet().find(surface) != mImplementation->getSurfaceSet().end();
}
+bool Display::isValidImage(const Image *image) const
+{
+ return mImageSet.find(const_cast<Image *>(image)) != mImageSet.end();
+}
+
bool Display::hasExistingWindowSurface(EGLNativeWindowType window)
{
WindowSurfaceMap *windowSurfaces = GetWindowSurfaces();
@@ -589,12 +872,25 @@ static ClientExtensions GenerateClientExtensions()
#if defined(ANGLE_ENABLE_D3D9) || defined(ANGLE_ENABLE_D3D11)
extensions.platformANGLED3D = true;
+ extensions.platformDevice = true;
#endif
#if defined(ANGLE_ENABLE_OPENGL)
extensions.platformANGLEOpenGL = true;
#endif
+#if defined(ANGLE_ENABLE_D3D11)
+ extensions.deviceCreation = true;
+ extensions.deviceCreationD3D11 = true;
+ extensions.experimentalPresentPath = true;
+#endif
+
+#if defined(ANGLE_USE_X11)
+ extensions.x11Visual = true;
+#endif
+
+ extensions.clientGetAllProcAddresses = true;
+
return extensions;
}
@@ -623,6 +919,10 @@ const std::string &Display::getClientExtensionString()
void Display::initDisplayExtensions()
{
mDisplayExtensions = mImplementation->getExtensions();
+
+ // Force EGL_KHR_get_all_proc_addresses on.
+ mDisplayExtensions.getAllProcAddresses = true;
+
mDisplayExtensionString = GenerateExtensionsString(mDisplayExtensions);
}
@@ -631,6 +931,29 @@ bool Display::isValidNativeWindow(EGLNativeWindowType window) const
return mImplementation->isValidNativeWindow(window);
}
+bool Display::isValidDisplay(const egl::Display *display)
+{
+ const ANGLEPlatformDisplayMap *anglePlatformDisplayMap = GetANGLEPlatformDisplayMap();
+ for (const auto &displayPair : *anglePlatformDisplayMap)
+ {
+ if (displayPair.second == display)
+ {
+ return true;
+ }
+ }
+
+ const DevicePlatformDisplayMap *devicePlatformDisplayMap = GetDevicePlatformDisplayMap();
+ for (const auto &displayPair : *devicePlatformDisplayMap)
+ {
+ if (displayPair.second == display)
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
bool Display::isValidNativeDisplay(EGLNativeDisplayType display)
{
// TODO(jmadill): handle this properly
@@ -672,4 +995,9 @@ const std::string &Display::getVendorString() const
return mVendorString;
}
+Device *Display::getDevice() const
+{
+ return mDevice;
+}
+
}
diff --git a/src/3rdparty/angle/src/libANGLE/Display.h b/src/3rdparty/angle/src/libANGLE/Display.h
index 5ab3f9c0e9..f80e308347 100644
--- a/src/3rdparty/angle/src/libANGLE/Display.h
+++ b/src/3rdparty/angle/src/libANGLE/Display.h
@@ -18,6 +18,7 @@
#include "libANGLE/Caps.h"
#include "libANGLE/Config.h"
#include "libANGLE/AttributeMap.h"
+#include "libANGLE/renderer/Renderer.h"
namespace gl
{
@@ -31,6 +32,8 @@ class DisplayImpl;
namespace egl
{
+class Device;
+class Image;
class Surface;
class Display final : angle::NonCopyable
@@ -41,7 +44,8 @@ class Display final : angle::NonCopyable
Error initialize();
void terminate();
- static egl::Display *getDisplay(EGLNativeDisplayType displayId, const AttributeMap &attribMap);
+ static egl::Display *GetDisplayFromDevice(void *native_display);
+ static egl::Display *GetDisplayFromAttribs(void *native_display, const AttributeMap &attribMap);
static const ClientExtensions &getClientExtensions();
static const std::string &getClientExtensionString();
@@ -57,20 +61,29 @@ class Display final : angle::NonCopyable
Error createPixmapSurface(const Config *configuration, NativePixmapType nativePixmap, const AttributeMap &attribs,
Surface **outSurface);
+ Error createImage(gl::Context *context,
+ EGLenum target,
+ EGLClientBuffer buffer,
+ const AttributeMap &attribs,
+ Image **outImage);
+
Error createContext(const Config *configuration, gl::Context *shareContext, const AttributeMap &attribs,
gl::Context **outContext);
Error makeCurrent(egl::Surface *drawSurface, egl::Surface *readSurface, gl::Context *context);
void destroySurface(egl::Surface *surface);
+ void destroyImage(egl::Image *image);
void destroyContext(gl::Context *context);
bool isInitialized() const;
bool isValidConfig(const Config *config) const;
bool isValidContext(gl::Context *context) const;
bool isValidSurface(egl::Surface *surface) const;
+ bool isValidImage(const Image *image) const;
bool isValidNativeWindow(EGLNativeWindowType window) const;
+ static bool isValidDisplay(const egl::Display *display);
static bool isValidNativeDisplay(EGLNativeDisplayType display);
static bool hasExistingWindowSurface(EGLNativeWindowType window);
@@ -78,6 +91,9 @@ class Display final : angle::NonCopyable
bool testDeviceLost();
void notifyDeviceLost();
+ Error waitClient() const;
+ Error waitNative(EGLint engine, egl::Surface *drawSurface, egl::Surface *readSurface) const;
+
const Caps &getCaps() const;
const DisplayExtensions &getExtensions() const;
@@ -88,9 +104,11 @@ class Display final : angle::NonCopyable
EGLNativeDisplayType getNativeDisplayId() const { return mDisplayId; }
rx::DisplayImpl *getImplementation() { return mImplementation; }
+ Device *getDevice() const;
+ EGLenum getPlatform() const { return mPlatform; }
private:
- Display(EGLNativeDisplayType displayId);
+ Display(EGLenum platform, EGLNativeDisplayType displayId, Device *eglDevice);
void setAttributes(rx::DisplayImpl *impl, const AttributeMap &attribMap);
@@ -109,6 +127,9 @@ class Display final : angle::NonCopyable
typedef std::set<gl::Context*> ContextSet;
ContextSet mContextSet;
+ typedef std::set<Image *> ImageSet;
+ ImageSet mImageSet;
+
bool mInitialized;
Caps mCaps;
@@ -117,6 +138,9 @@ class Display final : angle::NonCopyable
std::string mDisplayExtensionString;
std::string mVendorString;
+
+ Device *mDevice;
+ EGLenum mPlatform;
};
}
diff --git a/src/3rdparty/angle/src/libANGLE/Error.cpp b/src/3rdparty/angle/src/libANGLE/Error.cpp
index e17f26bec4..fed1594972 100644
--- a/src/3rdparty/angle/src/libANGLE/Error.cpp
+++ b/src/3rdparty/angle/src/libANGLE/Error.cpp
@@ -16,9 +16,16 @@
namespace gl
{
-Error::Error(GLenum errorCode, const char *msg, ...)
- : mCode(errorCode),
- mMessage(nullptr)
+Error::Error(GLenum errorCode, const char *msg, ...) : mCode(errorCode), mID(errorCode)
+{
+ va_list vararg;
+ va_start(vararg, msg);
+ createMessageString();
+ *mMessage = FormatString(msg, vararg);
+ va_end(vararg);
+}
+
+Error::Error(GLenum errorCode, GLuint id, const char *msg, ...) : mCode(errorCode), mID(id)
{
va_list vararg;
va_start(vararg, msg);
@@ -29,9 +36,9 @@ Error::Error(GLenum errorCode, const char *msg, ...)
void Error::createMessageString() const
{
- if (mMessage == nullptr)
+ if (!mMessage)
{
- mMessage = new std::string();
+ mMessage.reset(new std::string);
}
}
@@ -41,15 +48,28 @@ const std::string &Error::getMessage() const
return *mMessage;
}
+bool Error::operator==(const Error &other) const
+{
+ if (mCode != other.mCode)
+ return false;
+
+ // TODO(jmadill): Compare extended error codes instead of strings.
+ if ((!mMessage || !other.mMessage) && (!mMessage != !other.mMessage))
+ return false;
+
+ return (*mMessage == *other.mMessage);
+}
+
+bool Error::operator!=(const Error &other) const
+{
+ return !(*this == other);
+}
}
namespace egl
{
-Error::Error(EGLint errorCode, const char *msg, ...)
- : mCode(errorCode),
- mID(0),
- mMessage(nullptr)
+Error::Error(EGLint errorCode, const char *msg, ...) : mCode(errorCode), mID(0)
{
va_list vararg;
va_start(vararg, msg);
@@ -58,10 +78,7 @@ Error::Error(EGLint errorCode, const char *msg, ...)
va_end(vararg);
}
-Error::Error(EGLint errorCode, EGLint id, const char *msg, ...)
- : mCode(errorCode),
- mID(id),
- mMessage(nullptr)
+Error::Error(EGLint errorCode, EGLint id, const char *msg, ...) : mCode(errorCode), mID(id)
{
va_list vararg;
va_start(vararg, msg);
@@ -69,11 +86,12 @@ Error::Error(EGLint errorCode, EGLint id, const char *msg, ...)
*mMessage = FormatString(msg, vararg);
va_end(vararg);
}
+
void Error::createMessageString() const
{
- if (mMessage == nullptr)
+ if (!mMessage)
{
- mMessage = new std::string();
+ mMessage.reset(new std::string);
}
}
diff --git a/src/3rdparty/angle/src/libANGLE/Error.h b/src/3rdparty/angle/src/libANGLE/Error.h
index 896b777567..a5f760956a 100644
--- a/src/3rdparty/angle/src/libANGLE/Error.h
+++ b/src/3rdparty/angle/src/libANGLE/Error.h
@@ -10,10 +10,10 @@
#define LIBANGLE_ERROR_H_
#include "angle_gl.h"
-#include "common/platform.h"
#include <EGL/egl.h>
#include <string>
+#include <memory>
namespace gl
{
@@ -23,27 +23,48 @@ class Error final
public:
explicit inline Error(GLenum errorCode);
Error(GLenum errorCode, const char *msg, ...);
+ Error(GLenum errorCode, GLuint id, const char *msg, ...);
inline Error(const Error &other);
inline Error(Error &&other);
- inline ~Error();
-
inline Error &operator=(const Error &other);
inline Error &operator=(Error &&other);
inline GLenum getCode() const;
+ inline GLuint getID() const;
inline bool isError() const;
const std::string &getMessage() const;
+ // Useful for mocking and testing
+ bool operator==(const Error &other) const;
+ bool operator!=(const Error &other) const;
+
private:
void createMessageString() const;
GLenum mCode;
- mutable std::string *mMessage;
+ GLuint mID;
+ mutable std::unique_ptr<std::string> mMessage;
+};
+
+template <typename T>
+class ErrorOrResult
+{
+ public:
+ ErrorOrResult(const gl::Error &error) : mError(error) {}
+ ErrorOrResult(T &&result) : mError(GL_NO_ERROR), mResult(std::move(result)) {}
+
+ bool isError() const { return mError.isError(); }
+ const gl::Error &getError() const { return mError; }
+ T &&getResult() { return std::move(mResult); }
+
+ private:
+ Error mError;
+ T mResult;
};
-}
+} // namespace gl
namespace egl
{
@@ -57,8 +78,6 @@ class Error final
inline Error(const Error &other);
inline Error(Error &&other);
- inline ~Error();
-
inline Error &operator=(const Error &other);
inline Error &operator=(Error &&other);
@@ -73,10 +92,10 @@ class Error final
EGLint mCode;
EGLint mID;
- mutable std::string *mMessage;
+ mutable std::unique_ptr<std::string> mMessage;
};
-}
+} // namespace egl
#include "Error.inl"
diff --git a/src/3rdparty/angle/src/libANGLE/Error.inl b/src/3rdparty/angle/src/libANGLE/Error.inl
index 32e8f05828..900fc5fd03 100644
--- a/src/3rdparty/angle/src/libANGLE/Error.inl
+++ b/src/3rdparty/angle/src/libANGLE/Error.inl
@@ -15,15 +15,15 @@ namespace gl
Error::Error(GLenum errorCode)
: mCode(errorCode),
- mMessage(nullptr)
+ mID(errorCode)
{
}
Error::Error(const Error &other)
: mCode(other.mCode),
- mMessage(nullptr)
+ mID(other.mID)
{
- if (other.mMessage != nullptr)
+ if (other.mMessage)
{
createMessageString();
*mMessage = *(other.mMessage);
@@ -32,28 +32,24 @@ Error::Error(const Error &other)
Error::Error(Error &&other)
: mCode(other.mCode),
- mMessage(other.mMessage)
-{
- other.mMessage = nullptr;
-}
-
-Error::~Error()
+ mID(other.mID),
+ mMessage(std::move(other.mMessage))
{
- SafeDelete(mMessage);
}
Error &Error::operator=(const Error &other)
{
mCode = other.mCode;
+ mID = other.mID;
- if (other.mMessage != nullptr)
+ if (other.mMessage)
{
createMessageString();
*mMessage = *(other.mMessage);
}
else
{
- SafeDelete(mMessage);
+ mMessage.release();
}
return *this;
@@ -61,10 +57,12 @@ Error &Error::operator=(const Error &other)
Error &Error::operator=(Error &&other)
{
- mCode = other.mCode;
- mMessage = other.mMessage;
-
- other.mMessage = nullptr;
+ if (this != &other)
+ {
+ mCode = other.mCode;
+ mID = other.mID;
+ mMessage = std::move(other.mMessage);
+ }
return *this;
}
@@ -74,6 +72,11 @@ GLenum Error::getCode() const
return mCode;
}
+GLuint Error::getID() const
+{
+ return mID;
+}
+
bool Error::isError() const
{
return (mCode != GL_NO_ERROR);
@@ -86,17 +89,15 @@ namespace egl
Error::Error(EGLint errorCode)
: mCode(errorCode),
- mID(0),
- mMessage(nullptr)
+ mID(0)
{
}
Error::Error(const Error &other)
: mCode(other.mCode),
- mID(other.mID),
- mMessage(nullptr)
+ mID(other.mID)
{
- if (other.mMessage != nullptr)
+ if (other.mMessage)
{
createMessageString();
*mMessage = *(other.mMessage);
@@ -106,14 +107,8 @@ Error::Error(const Error &other)
Error::Error(Error &&other)
: mCode(other.mCode),
mID(other.mID),
- mMessage(other.mMessage)
-{
- other.mMessage = nullptr;
-}
-
-Error::~Error()
+ mMessage(std::move(other.mMessage))
{
- SafeDelete(mMessage);
}
Error &Error::operator=(const Error &other)
@@ -121,14 +116,14 @@ Error &Error::operator=(const Error &other)
mCode = other.mCode;
mID = other.mID;
- if (other.mMessage != nullptr)
+ if (other.mMessage)
{
createMessageString();
*mMessage = *(other.mMessage);
}
else
{
- SafeDelete(mMessage);
+ mMessage.release();
}
return *this;
@@ -136,11 +131,12 @@ Error &Error::operator=(const Error &other)
Error &Error::operator=(Error &&other)
{
- mCode = other.mCode;
- mID = other.mID;
- mMessage = other.mMessage;
-
- other.mMessage = nullptr;
+ if (this != &other)
+ {
+ mCode = other.mCode;
+ mID = other.mID;
+ mMessage = std::move(other.mMessage);
+ }
return *this;
}
diff --git a/src/3rdparty/angle/src/libANGLE/Fence.cpp b/src/3rdparty/angle/src/libANGLE/Fence.cpp
index 8ab4cc9daa..ff32f4bbe9 100644
--- a/src/3rdparty/angle/src/libANGLE/Fence.cpp
+++ b/src/3rdparty/angle/src/libANGLE/Fence.cpp
@@ -32,16 +32,9 @@ FenceNV::~FenceNV()
SafeDelete(mFence);
}
-GLboolean FenceNV::isFence() const
+Error FenceNV::set(GLenum condition)
{
- // GL_NV_fence spec:
- // A name returned by GenFencesNV, but not yet set via SetFenceNV, is not the name of an existing fence.
- return (mIsSet ? GL_TRUE : GL_FALSE);
-}
-
-Error FenceNV::setFence(GLenum condition)
-{
- Error error = mFence->set();
+ Error error = mFence->set(condition);
if (error.isError())
{
return error;
@@ -54,10 +47,10 @@ Error FenceNV::setFence(GLenum condition)
return Error(GL_NO_ERROR);
}
-Error FenceNV::testFence(GLboolean *outResult)
+Error FenceNV::test(GLboolean *outResult)
{
// Flush the command buffer by default
- Error error = mFence->test(true, &mStatus);
+ Error error = mFence->test(&mStatus);
if (error.isError())
{
return error;
@@ -67,17 +60,23 @@ Error FenceNV::testFence(GLboolean *outResult)
return Error(GL_NO_ERROR);
}
-Error FenceNV::finishFence()
+Error FenceNV::finish()
{
ASSERT(mIsSet);
- return mFence->finishFence(&mStatus);
+ gl::Error error = mFence->finish();
+ if (error.isError())
+ {
+ return error;
+ }
+
+ mStatus = GL_TRUE;
+
+ return Error(GL_NO_ERROR);
}
FenceSync::FenceSync(rx::FenceSyncImpl *impl, GLuint id)
- : RefCountObject(id),
- mFence(impl),
- mCondition(GL_NONE)
+ : RefCountObject(id), mFence(impl), mLabel(), mCondition(GL_NONE), mFlags(0)
{
}
@@ -86,15 +85,26 @@ FenceSync::~FenceSync()
SafeDelete(mFence);
}
-Error FenceSync::set(GLenum condition)
+void FenceSync::setLabel(const std::string &label)
+{
+ mLabel = label;
+}
+
+const std::string &FenceSync::getLabel() const
+{
+ return mLabel;
+}
+
+Error FenceSync::set(GLenum condition, GLbitfield flags)
{
- Error error = mFence->set();
+ Error error = mFence->set(condition, flags);
if (error.isError())
{
return error;
}
mCondition = condition;
+ mFlags = flags;
return Error(GL_NO_ERROR);
}
diff --git a/src/3rdparty/angle/src/libANGLE/Fence.h b/src/3rdparty/angle/src/libANGLE/Fence.h
index bcd66b6831..b2daed6f0e 100644
--- a/src/3rdparty/angle/src/libANGLE/Fence.h
+++ b/src/3rdparty/angle/src/libANGLE/Fence.h
@@ -10,6 +10,7 @@
#ifndef LIBANGLE_FENCE_H_
#define LIBANGLE_FENCE_H_
+#include "libANGLE/Debug.h"
#include "libANGLE/Error.h"
#include "libANGLE/RefCountObject.h"
@@ -30,11 +31,11 @@ class FenceNV final : angle::NonCopyable
explicit FenceNV(rx::FenceNVImpl *impl);
virtual ~FenceNV();
- GLboolean isFence() const;
- Error setFence(GLenum condition);
- Error testFence(GLboolean *outResult);
- Error finishFence();
+ Error set(GLenum condition);
+ Error test(GLboolean *outResult);
+ Error finish();
+ bool isSet() const { return mIsSet; }
GLboolean getStatus() const { return mStatus; }
GLenum getCondition() const { return mCondition; }
@@ -47,23 +48,30 @@ class FenceNV final : angle::NonCopyable
GLenum mCondition;
};
-class FenceSync final : public RefCountObject
+class FenceSync final : public RefCountObject, public LabeledObject
{
public:
- explicit FenceSync(rx::FenceSyncImpl *impl, GLuint id);
+ FenceSync(rx::FenceSyncImpl *impl, GLuint id);
virtual ~FenceSync();
- Error set(GLenum condition);
+ void setLabel(const std::string &label) override;
+ const std::string &getLabel() const override;
+
+ Error set(GLenum condition, GLbitfield flags);
Error clientWait(GLbitfield flags, GLuint64 timeout, GLenum *outResult);
Error serverWait(GLbitfield flags, GLuint64 timeout);
Error getStatus(GLint *outResult) const;
GLenum getCondition() const { return mCondition; }
+ GLbitfield getFlags() const { return mFlags; }
private:
rx::FenceSyncImpl *mFence;
+ std::string mLabel;
+
GLenum mCondition;
+ GLbitfield mFlags;
};
}
diff --git a/src/3rdparty/angle/src/libANGLE/Framebuffer.cpp b/src/3rdparty/angle/src/libANGLE/Framebuffer.cpp
index b1dd4a1b0f..3def57b87e 100644
--- a/src/3rdparty/angle/src/libANGLE/Framebuffer.cpp
+++ b/src/3rdparty/angle/src/libANGLE/Framebuffer.cpp
@@ -9,6 +9,7 @@
#include "libANGLE/Framebuffer.h"
+#include "common/Optional.h"
#include "common/utilities.h"
#include "libANGLE/Config.h"
#include "libANGLE/Context.h"
@@ -20,81 +21,164 @@
#include "libANGLE/renderer/FramebufferImpl.h"
#include "libANGLE/renderer/ImplFactory.h"
#include "libANGLE/renderer/RenderbufferImpl.h"
-#include "libANGLE/renderer/Workarounds.h"
+#include "libANGLE/renderer/SurfaceImpl.h"
namespace gl
{
namespace
{
-void DeleteMatchingAttachment(FramebufferAttachment *&attachment, GLenum matchType, GLuint matchId)
+void DetachMatchingAttachment(FramebufferAttachment *attachment, GLenum matchType, GLuint matchId)
{
- if (attachment && attachment->type() == matchType && attachment->id() == matchId)
+ if (attachment->isAttached() &&
+ attachment->type() == matchType &&
+ attachment->id() == matchId)
{
- SafeDelete(attachment);
+ attachment->detach();
}
}
}
+Framebuffer::Data::Data()
+ : mLabel(),
+ mColorAttachments(1),
+ mDrawBufferStates(1, GL_NONE),
+ mReadBufferState(GL_COLOR_ATTACHMENT0_EXT)
+{
+ mDrawBufferStates[0] = GL_COLOR_ATTACHMENT0_EXT;
+}
+
Framebuffer::Data::Data(const Caps &caps)
- : mColorAttachments(caps.maxColorAttachments, nullptr),
- mDepthAttachment(nullptr),
- mStencilAttachment(nullptr),
+ : mLabel(),
+ mColorAttachments(caps.maxColorAttachments),
mDrawBufferStates(caps.maxDrawBuffers, GL_NONE),
mReadBufferState(GL_COLOR_ATTACHMENT0_EXT)
{
+ ASSERT(mDrawBufferStates.size() > 0);
mDrawBufferStates[0] = GL_COLOR_ATTACHMENT0_EXT;
}
Framebuffer::Data::~Data()
{
- for (auto it = mColorAttachments.begin(); it != mColorAttachments.end(); ++it)
- {
- SafeDelete(*it);
- }
- SafeDelete(mDepthAttachment);
- SafeDelete(mStencilAttachment);
}
-FramebufferAttachment *Framebuffer::Data::getReadAttachment() const
+const std::string &Framebuffer::Data::getLabel()
+{
+ return mLabel;
+}
+
+const FramebufferAttachment *Framebuffer::Data::getReadAttachment() const
{
ASSERT(mReadBufferState == GL_BACK || (mReadBufferState >= GL_COLOR_ATTACHMENT0 && mReadBufferState <= GL_COLOR_ATTACHMENT15));
size_t readIndex = (mReadBufferState == GL_BACK ? 0 : static_cast<size_t>(mReadBufferState - GL_COLOR_ATTACHMENT0));
ASSERT(readIndex < mColorAttachments.size());
- return mColorAttachments[readIndex];
+ return mColorAttachments[readIndex].isAttached() ? &mColorAttachments[readIndex] : nullptr;
}
-FramebufferAttachment *Framebuffer::Data::getFirstColorAttachment() const
+const FramebufferAttachment *Framebuffer::Data::getFirstColorAttachment() const
{
- for (auto it = mColorAttachments.cbegin(); it != mColorAttachments.cend(); ++it)
+ for (const FramebufferAttachment &colorAttachment : mColorAttachments)
{
- if (*it != nullptr)
+ if (colorAttachment.isAttached())
{
- return *it;
+ return &colorAttachment;
}
}
return nullptr;
}
-FramebufferAttachment *Framebuffer::Data::getDepthOrStencilAttachment() const
+const FramebufferAttachment *Framebuffer::Data::getDepthOrStencilAttachment() const
{
- return (mDepthAttachment != nullptr ? mDepthAttachment : mStencilAttachment);
+ if (mDepthAttachment.isAttached())
+ {
+ return &mDepthAttachment;
+ }
+ if (mStencilAttachment.isAttached())
+ {
+ return &mStencilAttachment;
+ }
+ return nullptr;
}
-Framebuffer::Framebuffer(const Caps &caps, rx::ImplFactory *factory, GLuint id)
- : mData(caps),
- mImpl(nullptr),
- mId(id)
+const FramebufferAttachment *Framebuffer::Data::getColorAttachment(size_t colorAttachment) const
{
- if (mId == 0)
+ ASSERT(colorAttachment < mColorAttachments.size());
+ return mColorAttachments[colorAttachment].isAttached() ?
+ &mColorAttachments[colorAttachment] :
+ nullptr;
+}
+
+const FramebufferAttachment *Framebuffer::Data::getDepthAttachment() const
+{
+ return mDepthAttachment.isAttached() ? &mDepthAttachment : nullptr;
+}
+
+const FramebufferAttachment *Framebuffer::Data::getStencilAttachment() const
+{
+ return mStencilAttachment.isAttached() ? &mStencilAttachment : nullptr;
+}
+
+const FramebufferAttachment *Framebuffer::Data::getDepthStencilAttachment() const
+{
+ // A valid depth-stencil attachment has the same resource bound to both the
+ // depth and stencil attachment points.
+ if (mDepthAttachment.isAttached() && mStencilAttachment.isAttached() &&
+ mDepthAttachment.type() == mStencilAttachment.type() &&
+ mDepthAttachment.id() == mStencilAttachment.id())
{
- mImpl = factory->createDefaultFramebuffer(mData);
+ return &mDepthAttachment;
}
- else
+
+ return nullptr;
+}
+
+bool Framebuffer::Data::attachmentsHaveSameDimensions() const
+{
+ Optional<Extents> attachmentSize;
+
+ auto hasMismatchedSize = [&attachmentSize](const FramebufferAttachment &attachment)
+ {
+ if (!attachment.isAttached())
+ {
+ return false;
+ }
+
+ if (!attachmentSize.valid())
+ {
+ attachmentSize = attachment.getSize();
+ return false;
+ }
+
+ return (attachment.getSize() != attachmentSize.value());
+ };
+
+ for (const auto &attachment : mColorAttachments)
+ {
+ if (hasMismatchedSize(attachment))
+ {
+ return false;
+ }
+ }
+
+ if (hasMismatchedSize(mDepthAttachment))
{
- mImpl = factory->createFramebuffer(mData);
+ return false;
}
+
+ return !hasMismatchedSize(mStencilAttachment);
+}
+
+Framebuffer::Framebuffer(const Caps &caps, rx::ImplFactory *factory, GLuint id)
+ : mData(caps), mImpl(factory->createFramebuffer(mData)), mId(id)
+{
+ ASSERT(mId != 0);
+ ASSERT(mImpl != nullptr);
+}
+
+Framebuffer::Framebuffer(rx::SurfaceImpl *surface)
+ : mData(), mImpl(surface->createDefaultFramebuffer(mData)), mId(0)
+{
ASSERT(mImpl != nullptr);
}
@@ -103,6 +187,16 @@ Framebuffer::~Framebuffer()
SafeDelete(mImpl);
}
+void Framebuffer::setLabel(const std::string &label)
+{
+ mData.mLabel = label;
+}
+
+const std::string &Framebuffer::getLabel() const
+{
+ return mData.mLabel;
+}
+
void Framebuffer::detachTexture(GLuint textureId)
{
detachResourceById(GL_TEXTURE, textureId);
@@ -115,62 +209,61 @@ void Framebuffer::detachRenderbuffer(GLuint renderbufferId)
void Framebuffer::detachResourceById(GLenum resourceType, GLuint resourceId)
{
- for (auto it = mData.mColorAttachments.begin(); it != mData.mColorAttachments.end(); ++it)
+ for (auto &colorAttachment : mData.mColorAttachments)
{
- DeleteMatchingAttachment(*it, resourceType, resourceId);
+ DetachMatchingAttachment(&colorAttachment, resourceType, resourceId);
}
- DeleteMatchingAttachment(mData.mDepthAttachment, resourceType, resourceId);
- DeleteMatchingAttachment(mData.mStencilAttachment, resourceType, resourceId);
+ DetachMatchingAttachment(&mData.mDepthAttachment, resourceType, resourceId);
+ DetachMatchingAttachment(&mData.mStencilAttachment, resourceType, resourceId);
}
-FramebufferAttachment *Framebuffer::getColorbuffer(unsigned int colorAttachment) const
+const FramebufferAttachment *Framebuffer::getColorbuffer(size_t colorAttachment) const
{
- ASSERT(colorAttachment < mData.mColorAttachments.size());
- return mData.mColorAttachments[colorAttachment];
+ return mData.getColorAttachment(colorAttachment);
}
-FramebufferAttachment *Framebuffer::getDepthbuffer() const
+const FramebufferAttachment *Framebuffer::getDepthbuffer() const
{
- return mData.mDepthAttachment;
+ return mData.getDepthAttachment();
}
-FramebufferAttachment *Framebuffer::getStencilbuffer() const
+const FramebufferAttachment *Framebuffer::getStencilbuffer() const
{
- return mData.mStencilAttachment;
+ return mData.getStencilAttachment();
}
-FramebufferAttachment *Framebuffer::getDepthStencilBuffer() const
+const FramebufferAttachment *Framebuffer::getDepthStencilBuffer() const
{
- return (hasValidDepthStencil() ? mData.mDepthAttachment : NULL);
+ return mData.getDepthStencilAttachment();
}
-FramebufferAttachment *Framebuffer::getDepthOrStencilbuffer() const
+const FramebufferAttachment *Framebuffer::getDepthOrStencilbuffer() const
{
return mData.getDepthOrStencilAttachment();
}
-FramebufferAttachment *Framebuffer::getReadColorbuffer() const
+const FramebufferAttachment *Framebuffer::getReadColorbuffer() const
{
return mData.getReadAttachment();
}
GLenum Framebuffer::getReadColorbufferType() const
{
- FramebufferAttachment *readAttachment = mData.getReadAttachment();
- return (readAttachment ? readAttachment->type() : GL_NONE);
+ const FramebufferAttachment *readAttachment = mData.getReadAttachment();
+ return (readAttachment != nullptr ? readAttachment->type() : GL_NONE);
}
-FramebufferAttachment *Framebuffer::getFirstColorbuffer() const
+const FramebufferAttachment *Framebuffer::getFirstColorbuffer() const
{
return mData.getFirstColorAttachment();
}
-FramebufferAttachment *Framebuffer::getAttachment(GLenum attachment) const
+const FramebufferAttachment *Framebuffer::getAttachment(GLenum attachment) const
{
if (attachment >= GL_COLOR_ATTACHMENT0 && attachment <= GL_COLOR_ATTACHMENT15)
{
- return getColorbuffer(attachment - GL_COLOR_ATTACHMENT0);
+ return mData.getColorAttachment(attachment - GL_COLOR_ATTACHMENT0);
}
else
{
@@ -178,27 +271,32 @@ FramebufferAttachment *Framebuffer::getAttachment(GLenum attachment) const
{
case GL_COLOR:
case GL_BACK:
- return getColorbuffer(0);
+ return mData.getColorAttachment(0);
case GL_DEPTH:
case GL_DEPTH_ATTACHMENT:
- return getDepthbuffer();
+ return mData.getDepthAttachment();
case GL_STENCIL:
case GL_STENCIL_ATTACHMENT:
- return getStencilbuffer();
+ return mData.getStencilAttachment();
case GL_DEPTH_STENCIL:
case GL_DEPTH_STENCIL_ATTACHMENT:
return getDepthStencilBuffer();
default:
UNREACHABLE();
- return NULL;
+ return nullptr;
}
}
}
-GLenum Framebuffer::getDrawBufferState(unsigned int colorAttachment) const
+size_t Framebuffer::getDrawbufferStateCount() const
{
- ASSERT(colorAttachment < mData.mDrawBufferStates.size());
- return mData.mDrawBufferStates[colorAttachment];
+ return mData.mDrawBufferStates.size();
+}
+
+GLenum Framebuffer::getDrawBufferState(size_t drawBuffer) const
+{
+ ASSERT(drawBuffer < mData.mDrawBufferStates.size());
+ return mData.mDrawBufferStates[drawBuffer];
}
void Framebuffer::setDrawBuffers(size_t count, const GLenum *buffers)
@@ -208,7 +306,37 @@ void Framebuffer::setDrawBuffers(size_t count, const GLenum *buffers)
ASSERT(count <= drawStates.size());
std::copy(buffers, buffers + count, drawStates.begin());
std::fill(drawStates.begin() + count, drawStates.end(), GL_NONE);
- mImpl->setDrawBuffers(count, buffers);
+ mDirtyBits.set(DIRTY_BIT_DRAW_BUFFERS);
+}
+
+const FramebufferAttachment *Framebuffer::getDrawBuffer(size_t drawBuffer) const
+{
+ ASSERT(drawBuffer < mData.mDrawBufferStates.size());
+ if (mData.mDrawBufferStates[drawBuffer] != GL_NONE)
+ {
+ // ES3 spec: "If the GL is bound to a draw framebuffer object, the ith buffer listed in bufs
+ // must be COLOR_ATTACHMENTi or NONE"
+ ASSERT(mData.mDrawBufferStates[drawBuffer] == GL_COLOR_ATTACHMENT0 + drawBuffer ||
+ (drawBuffer == 0 && mData.mDrawBufferStates[drawBuffer] == GL_BACK));
+ return getAttachment(mData.mDrawBufferStates[drawBuffer]);
+ }
+ else
+ {
+ return nullptr;
+ }
+}
+
+bool Framebuffer::hasEnabledDrawBuffer() const
+{
+ for (size_t drawbufferIdx = 0; drawbufferIdx < mData.mDrawBufferStates.size(); ++drawbufferIdx)
+ {
+ if (getDrawBuffer(drawbufferIdx) != nullptr)
+ {
+ return true;
+ }
+ }
+
+ return false;
}
GLenum Framebuffer::getReadBufferState() const
@@ -222,39 +350,29 @@ void Framebuffer::setReadBuffer(GLenum buffer)
(buffer >= GL_COLOR_ATTACHMENT0 &&
(buffer - GL_COLOR_ATTACHMENT0) < mData.mColorAttachments.size()));
mData.mReadBufferState = buffer;
- mImpl->setReadBuffer(buffer);
+ mDirtyBits.set(DIRTY_BIT_READ_BUFFER);
}
-bool Framebuffer::isEnabledColorAttachment(unsigned int colorAttachment) const
+size_t Framebuffer::getNumColorBuffers() const
{
- ASSERT(colorAttachment < mData.mColorAttachments.size());
- return (mData.mColorAttachments[colorAttachment] &&
- mData.mDrawBufferStates[colorAttachment] != GL_NONE);
+ return mData.mColorAttachments.size();
}
-bool Framebuffer::hasEnabledColorAttachment() const
+bool Framebuffer::hasDepth() const
{
- for (size_t colorAttachment = 0; colorAttachment < mData.mColorAttachments.size(); ++colorAttachment)
- {
- if (isEnabledColorAttachment(colorAttachment))
- {
- return true;
- }
- }
-
- return false;
+ return (mData.mDepthAttachment.isAttached() && mData.mDepthAttachment.getDepthSize() > 0);
}
bool Framebuffer::hasStencil() const
{
- return (mData.mStencilAttachment && mData.mStencilAttachment->getStencilSize() > 0);
+ return (mData.mStencilAttachment.isAttached() && mData.mStencilAttachment.getStencilSize() > 0);
}
bool Framebuffer::usingExtendedDrawBuffers() const
{
- for (size_t colorAttachment = 1; colorAttachment < mData.mColorAttachments.size(); ++colorAttachment)
+ for (size_t drawbufferIdx = 1; drawbufferIdx < mData.mDrawBufferStates.size(); ++drawbufferIdx)
{
- if (isEnabledColorAttachment(colorAttachment))
+ if (getDrawBuffer(drawbufferIdx) != nullptr)
{
return true;
}
@@ -272,38 +390,52 @@ GLenum Framebuffer::checkStatus(const gl::Data &data) const
return GL_FRAMEBUFFER_COMPLETE;
}
- int width = 0;
- int height = 0;
unsigned int colorbufferSize = 0;
int samples = -1;
bool missingAttachment = true;
- for (auto it = mData.mColorAttachments.cbegin(); it != mData.mColorAttachments.cend(); ++it)
+ for (const FramebufferAttachment &colorAttachment : mData.mColorAttachments)
{
- const auto &colorAttachment = *it;
- if (colorAttachment != nullptr)
+ if (colorAttachment.isAttached())
{
- if (colorAttachment->getWidth() == 0 || colorAttachment->getHeight() == 0)
+ const Extents &size = colorAttachment.getSize();
+ if (size.width == 0 || size.height == 0)
{
return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
}
- GLenum internalformat = colorAttachment->getInternalFormat();
+ GLenum internalformat = colorAttachment.getInternalFormat();
const TextureCaps &formatCaps = data.textureCaps->get(internalformat);
const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
- if (colorAttachment->type() == GL_TEXTURE)
+ if (colorAttachment.type() == GL_TEXTURE)
{
if (!formatCaps.renderable)
{
- return GL_FRAMEBUFFER_UNSUPPORTED;
+ return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
}
if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0)
{
return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
}
+
+ if (colorAttachment.layer() >= size.depth)
+ {
+ return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+ }
+
+ // ES3 specifies that cube map texture attachments must be cube complete.
+ // This language is missing from the ES2 spec, but we enforce it here because some
+ // desktop OpenGL drivers also enforce this validation.
+ // TODO(jmadill): Check if OpenGL ES2 drivers enforce cube completeness.
+ const Texture *texture = colorAttachment.getTexture();
+ ASSERT(texture);
+ if (texture->getTarget() == GL_TEXTURE_CUBE_MAP && !texture->isCubeComplete())
+ {
+ return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+ }
}
- else if (colorAttachment->type() == GL_RENDERBUFFER)
+ else if (colorAttachment.type() == GL_RENDERBUFFER)
{
if (!formatCaps.renderable || formatInfo.depthBits > 0 || formatInfo.stencilBits > 0)
{
@@ -313,15 +445,9 @@ GLenum Framebuffer::checkStatus(const gl::Data &data) const
if (!missingAttachment)
{
- // all color attachments must have the same width and height
- if (colorAttachment->getWidth() != width || colorAttachment->getHeight() != height)
- {
- return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
- }
-
// APPLE_framebuffer_multisample, which EXT_draw_buffers refers to, requires that
// all color attachments have the same number of samples for the FBO to be complete.
- if (colorAttachment->getSamples() != samples)
+ if (colorAttachment.getSamples() != samples)
{
return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT;
}
@@ -338,27 +464,26 @@ GLenum Framebuffer::checkStatus(const gl::Data &data) const
}
else
{
- width = colorAttachment->getWidth();
- height = colorAttachment->getHeight();
- samples = colorAttachment->getSamples();
+ samples = colorAttachment.getSamples();
colorbufferSize = formatInfo.pixelBytes;
missingAttachment = false;
}
}
}
- const FramebufferAttachment *depthAttachment = mData.mDepthAttachment;
- if (depthAttachment != nullptr)
+ const FramebufferAttachment &depthAttachment = mData.mDepthAttachment;
+ if (depthAttachment.isAttached())
{
- if (depthAttachment->getWidth() == 0 || depthAttachment->getHeight() == 0)
+ const Extents &size = depthAttachment.getSize();
+ if (size.width == 0 || size.height == 0)
{
return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
}
- GLenum internalformat = depthAttachment->getInternalFormat();
+ GLenum internalformat = depthAttachment.getInternalFormat();
const TextureCaps &formatCaps = data.textureCaps->get(internalformat);
const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
- if (depthAttachment->type() == GL_TEXTURE)
+ if (depthAttachment.type() == GL_TEXTURE)
{
// depth texture attachments require OES/ANGLE_depth_texture
if (!data.extensions->depthTextures)
@@ -368,7 +493,7 @@ GLenum Framebuffer::checkStatus(const gl::Data &data) const
if (!formatCaps.renderable)
{
- return GL_FRAMEBUFFER_UNSUPPORTED;
+ return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
}
if (formatInfo.depthBits == 0)
@@ -376,7 +501,7 @@ GLenum Framebuffer::checkStatus(const gl::Data &data) const
return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
}
}
- else if (depthAttachment->type() == GL_RENDERBUFFER)
+ else if (depthAttachment.type() == GL_RENDERBUFFER)
{
if (!formatCaps.renderable || formatInfo.depthBits == 0)
{
@@ -386,33 +511,28 @@ GLenum Framebuffer::checkStatus(const gl::Data &data) const
if (missingAttachment)
{
- width = depthAttachment->getWidth();
- height = depthAttachment->getHeight();
- samples = depthAttachment->getSamples();
+ samples = depthAttachment.getSamples();
missingAttachment = false;
}
- else if (width != depthAttachment->getWidth() || height != depthAttachment->getHeight())
- {
- return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
- }
- else if (samples != depthAttachment->getSamples())
+ else if (samples != depthAttachment.getSamples())
{
return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
}
}
- const FramebufferAttachment *stencilAttachment = mData.mStencilAttachment;
- if (stencilAttachment)
+ const FramebufferAttachment &stencilAttachment = mData.mStencilAttachment;
+ if (stencilAttachment.isAttached())
{
- if (stencilAttachment->getWidth() == 0 || stencilAttachment->getHeight() == 0)
+ const Extents &size = stencilAttachment.getSize();
+ if (size.width == 0 || size.height == 0)
{
return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
}
- GLenum internalformat = stencilAttachment->getInternalFormat();
+ GLenum internalformat = stencilAttachment.getInternalFormat();
const TextureCaps &formatCaps = data.textureCaps->get(internalformat);
const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
- if (stencilAttachment->type() == GL_TEXTURE)
+ if (stencilAttachment.type() == GL_TEXTURE)
{
// texture stencil attachments come along as part
// of OES_packed_depth_stencil + OES/ANGLE_depth_texture
@@ -423,7 +543,7 @@ GLenum Framebuffer::checkStatus(const gl::Data &data) const
if (!formatCaps.renderable)
{
- return GL_FRAMEBUFFER_UNSUPPORTED;
+ return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
}
if (formatInfo.stencilBits == 0)
@@ -431,7 +551,7 @@ GLenum Framebuffer::checkStatus(const gl::Data &data) const
return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
}
}
- else if (stencilAttachment->type() == GL_RENDERBUFFER)
+ else if (stencilAttachment.type() == GL_RENDERBUFFER)
{
if (!formatCaps.renderable || formatInfo.stencilBits == 0)
{
@@ -441,35 +561,40 @@ GLenum Framebuffer::checkStatus(const gl::Data &data) const
if (missingAttachment)
{
- width = stencilAttachment->getWidth();
- height = stencilAttachment->getHeight();
- samples = stencilAttachment->getSamples();
+ samples = stencilAttachment.getSamples();
missingAttachment = false;
}
- else if (width != stencilAttachment->getWidth() || height != stencilAttachment->getHeight())
- {
- return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
- }
- else if (samples != stencilAttachment->getSamples())
+ else if (samples != stencilAttachment.getSamples())
{
return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
}
}
- // if we have both a depth and stencil buffer, they must refer to the same object
- // since we only support packed_depth_stencil and not separate depth and stencil
- if (depthAttachment && stencilAttachment && !hasValidDepthStencil())
- {
- return GL_FRAMEBUFFER_UNSUPPORTED;
- }
-
// we need to have at least one attachment to be complete
if (missingAttachment)
{
return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
}
- return mImpl->checkStatus();
+ // In ES 2.0, all color attachments must have the same width and height.
+ // In ES 3.0, there is no such restriction.
+ if (data.clientVersion < 3 && !mData.attachmentsHaveSameDimensions())
+ {
+ return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
+ }
+
+ syncState();
+ if (!mImpl->checkStatus())
+ {
+ return GL_FRAMEBUFFER_UNSUPPORTED;
+ }
+
+ return GL_FRAMEBUFFER_COMPLETE;
+}
+
+Error Framebuffer::discard(size_t count, const GLenum *attachments)
+{
+ return mImpl->discard(count, attachments);
}
Error Framebuffer::invalidate(size_t count, const GLenum *attachments)
@@ -484,27 +609,65 @@ Error Framebuffer::invalidateSub(size_t count, const GLenum *attachments, const
Error Framebuffer::clear(const gl::Data &data, GLbitfield mask)
{
+ if (data.state->isRasterizerDiscardEnabled())
+ {
+ return gl::Error(GL_NO_ERROR);
+ }
+
return mImpl->clear(data, mask);
}
-Error Framebuffer::clearBufferfv(const State &state, GLenum buffer, GLint drawbuffer, const GLfloat *values)
+Error Framebuffer::clearBufferfv(const gl::Data &data,
+ GLenum buffer,
+ GLint drawbuffer,
+ const GLfloat *values)
{
- return mImpl->clearBufferfv(state, buffer, drawbuffer, values);
+ if (data.state->isRasterizerDiscardEnabled())
+ {
+ return gl::Error(GL_NO_ERROR);
+ }
+
+ return mImpl->clearBufferfv(data, buffer, drawbuffer, values);
}
-Error Framebuffer::clearBufferuiv(const State &state, GLenum buffer, GLint drawbuffer, const GLuint *values)
+Error Framebuffer::clearBufferuiv(const gl::Data &data,
+ GLenum buffer,
+ GLint drawbuffer,
+ const GLuint *values)
{
- return mImpl->clearBufferuiv(state, buffer, drawbuffer, values);
+ if (data.state->isRasterizerDiscardEnabled())
+ {
+ return gl::Error(GL_NO_ERROR);
+ }
+
+ return mImpl->clearBufferuiv(data, buffer, drawbuffer, values);
}
-Error Framebuffer::clearBufferiv(const State &state, GLenum buffer, GLint drawbuffer, const GLint *values)
+Error Framebuffer::clearBufferiv(const gl::Data &data,
+ GLenum buffer,
+ GLint drawbuffer,
+ const GLint *values)
{
- return mImpl->clearBufferiv(state, buffer, drawbuffer, values);
+ if (data.state->isRasterizerDiscardEnabled())
+ {
+ return gl::Error(GL_NO_ERROR);
+ }
+
+ return mImpl->clearBufferiv(data, buffer, drawbuffer, values);
}
-Error Framebuffer::clearBufferfi(const State &state, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil)
+Error Framebuffer::clearBufferfi(const gl::Data &data,
+ GLenum buffer,
+ GLint drawbuffer,
+ GLfloat depth,
+ GLint stencil)
{
- return mImpl->clearBufferfi(state, buffer, drawbuffer, depth, stencil);
+ if (data.state->isRasterizerDiscardEnabled())
+ {
+ return gl::Error(GL_NO_ERROR);
+ }
+
+ return mImpl->clearBufferfi(data, buffer, drawbuffer, depth, stencil);
}
GLenum Framebuffer::getImplementationColorReadFormat() const
@@ -517,13 +680,33 @@ GLenum Framebuffer::getImplementationColorReadType() const
return mImpl->getImplementationColorReadType();
}
-Error Framebuffer::readPixels(const gl::State &state, const gl::Rectangle &area, GLenum format, GLenum type, GLvoid *pixels) const
+Error Framebuffer::readPixels(const State &state,
+ const Rectangle &area,
+ GLenum format,
+ GLenum type,
+ GLvoid *pixels) const
{
- return mImpl->readPixels(state, area, format, type, pixels);
+ Error error = mImpl->readPixels(state, area, format, type, pixels);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ Buffer *unpackBuffer = state.getUnpackState().pixelBuffer.get();
+ if (unpackBuffer)
+ {
+ unpackBuffer->onPixelUnpack();
+ }
+
+ return Error(GL_NO_ERROR);
}
-Error Framebuffer::blit(const gl::State &state, const gl::Rectangle &sourceArea, const gl::Rectangle &destArea,
- GLbitfield mask, GLenum filter, const gl::Framebuffer *sourceFramebuffer)
+Error Framebuffer::blit(const State &state,
+ const Rectangle &sourceArea,
+ const Rectangle &destArea,
+ GLbitfield mask,
+ GLenum filter,
+ const Framebuffer *sourceFramebuffer)
{
return mImpl->blit(state, sourceArea, destArea, mask, filter, sourceFramebuffer);
}
@@ -534,11 +717,11 @@ int Framebuffer::getSamples(const gl::Data &data) const
{
// for a complete framebuffer, all attachments must have the same sample count
// in this case return the first nonzero sample size
- for (auto it = mData.mColorAttachments.cbegin(); it != mData.mColorAttachments.cend(); ++it)
+ for (const FramebufferAttachment &colorAttachment : mData.mColorAttachments)
{
- if (*it != nullptr)
+ if (colorAttachment.isAttached())
{
- return (*it)->getSamples();
+ return colorAttachment.getSamples();
}
}
}
@@ -548,111 +731,77 @@ int Framebuffer::getSamples(const gl::Data &data) const
bool Framebuffer::hasValidDepthStencil() const
{
- // A valid depth-stencil attachment has the same resource bound to both the
- // depth and stencil attachment points.
- return (mData.mDepthAttachment && mData.mStencilAttachment &&
- mData.mDepthAttachment->type() == mData.mStencilAttachment->type() &&
- mData.mDepthAttachment->id() == mData.mStencilAttachment->id());
-}
-
-void Framebuffer::setTextureAttachment(GLenum attachment, Texture *texture, const ImageIndex &imageIndex)
-{
- setAttachment(attachment, new TextureAttachment(attachment, texture, imageIndex));
+ return mData.getDepthStencilAttachment() != nullptr;
}
-void Framebuffer::setRenderbufferAttachment(GLenum attachment, Renderbuffer *renderbuffer)
+void Framebuffer::setAttachment(GLenum type,
+ GLenum binding,
+ const ImageIndex &textureIndex,
+ FramebufferAttachmentObject *resource)
{
- setAttachment(attachment, new RenderbufferAttachment(attachment, renderbuffer));
-}
-
-void Framebuffer::setNULLAttachment(GLenum attachment)
-{
- setAttachment(attachment, NULL);
-}
-
-void Framebuffer::setAttachment(GLenum attachment, FramebufferAttachment *attachmentObj)
-{
- if (attachment >= GL_COLOR_ATTACHMENT0 && attachment < (GL_COLOR_ATTACHMENT0 + mData.mColorAttachments.size()))
- {
- size_t colorAttachment = attachment - GL_COLOR_ATTACHMENT0;
- SafeDelete(mData.mColorAttachments[colorAttachment]);
- mData.mColorAttachments[colorAttachment] = attachmentObj;
- mImpl->setColorAttachment(colorAttachment, attachmentObj);
- }
- else if (attachment == GL_BACK)
- {
- SafeDelete(mData.mColorAttachments[0]);
- mData.mColorAttachments[0] = attachmentObj;
- mImpl->setColorAttachment(0, attachmentObj);
- }
- else if (attachment == GL_DEPTH_ATTACHMENT || attachment == GL_DEPTH)
- {
- SafeDelete(mData.mDepthAttachment);
- mData.mDepthAttachment = attachmentObj;
- mImpl->setDepthAttachment(attachmentObj);
- }
- else if (attachment == GL_STENCIL_ATTACHMENT || attachment == GL_STENCIL)
+ if (binding == GL_DEPTH_STENCIL || binding == GL_DEPTH_STENCIL_ATTACHMENT)
{
- SafeDelete(mData.mStencilAttachment);
- mData.mStencilAttachment = attachmentObj;
- mImpl->setStencilAttachment(attachmentObj);
- }
- else if (attachment == GL_DEPTH_STENCIL_ATTACHMENT || attachment == GL_DEPTH_STENCIL)
- {
- SafeDelete(mData.mDepthAttachment);
- SafeDelete(mData.mStencilAttachment);
-
// ensure this is a legitimate depth+stencil format
- if (attachmentObj && attachmentObj->getDepthSize() > 0 && attachmentObj->getStencilSize() > 0)
+ FramebufferAttachmentObject *attachmentObj = resource;
+ if (resource)
{
- mData.mDepthAttachment = attachmentObj;
- mImpl->setDepthAttachment(attachmentObj);
-
- // Make a new attachment object to ensure we do not double-delete
- // See angle issue 686
- if (attachmentObj->type() == GL_TEXTURE)
- {
- mData.mStencilAttachment = new TextureAttachment(GL_DEPTH_STENCIL_ATTACHMENT, attachmentObj->getTexture(),
- *attachmentObj->getTextureImageIndex());
- mImpl->setStencilAttachment(mData.mStencilAttachment);
- }
- else if (attachmentObj->type() == GL_RENDERBUFFER)
+ FramebufferAttachment::Target target(binding, textureIndex);
+ GLenum internalFormat = resource->getAttachmentInternalFormat(target);
+ const InternalFormat &formatInfo = GetInternalFormatInfo(internalFormat);
+ if (formatInfo.depthBits == 0 || formatInfo.stencilBits == 0)
{
- mData.mStencilAttachment = new RenderbufferAttachment(GL_DEPTH_STENCIL_ATTACHMENT, attachmentObj->getRenderbuffer());
- mImpl->setStencilAttachment(mData.mStencilAttachment);
- }
- else
- {
- UNREACHABLE();
+ // Attaching nullptr detaches the current attachment.
+ attachmentObj = nullptr;
}
}
+
+ mData.mDepthAttachment.attach(type, binding, textureIndex, attachmentObj);
+ mData.mStencilAttachment.attach(type, binding, textureIndex, attachmentObj);
+ mDirtyBits.set(DIRTY_BIT_DEPTH_ATTACHMENT);
+ mDirtyBits.set(DIRTY_BIT_STENCIL_ATTACHMENT);
}
else
{
- UNREACHABLE();
+ switch (binding)
+ {
+ case GL_DEPTH:
+ case GL_DEPTH_ATTACHMENT:
+ mData.mDepthAttachment.attach(type, binding, textureIndex, resource);
+ mDirtyBits.set(DIRTY_BIT_DEPTH_ATTACHMENT);
+ break;
+ case GL_STENCIL:
+ case GL_STENCIL_ATTACHMENT:
+ mData.mStencilAttachment.attach(type, binding, textureIndex, resource);
+ mDirtyBits.set(DIRTY_BIT_STENCIL_ATTACHMENT);
+ break;
+ case GL_BACK:
+ mData.mColorAttachments[0].attach(type, binding, textureIndex, resource);
+ mDirtyBits.set(DIRTY_BIT_COLOR_ATTACHMENT_0);
+ break;
+ default:
+ {
+ size_t colorIndex = binding - GL_COLOR_ATTACHMENT0;
+ ASSERT(colorIndex < mData.mColorAttachments.size());
+ mData.mColorAttachments[colorIndex].attach(type, binding, textureIndex, resource);
+ mDirtyBits.set(DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex);
+ }
+ break;
+ }
}
}
-DefaultFramebuffer::DefaultFramebuffer(const Caps &caps, rx::ImplFactory *factory, egl::Surface *surface)
- : Framebuffer(caps, factory, 0)
+void Framebuffer::resetAttachment(GLenum binding)
{
- const egl::Config *config = surface->getConfig();
-
- setAttachment(GL_BACK, new DefaultAttachment(GL_BACK, surface));
+ setAttachment(GL_NONE, binding, ImageIndex::MakeInvalid(), nullptr);
+}
- if (config->depthSize > 0)
- {
- setAttachment(GL_DEPTH, new DefaultAttachment(GL_DEPTH, surface));
- }
- if (config->stencilSize > 0)
+void Framebuffer::syncState() const
+{
+ if (mDirtyBits.any())
{
- setAttachment(GL_STENCIL, new DefaultAttachment(GL_STENCIL, surface));
+ mImpl->syncState(mDirtyBits);
+ mDirtyBits.reset();
}
-
- GLenum drawBufferState = GL_BACK;
- setDrawBuffers(1, &drawBufferState);
-
- setReadBuffer(GL_BACK);
}
-}
+} // namespace gl
diff --git a/src/3rdparty/angle/src/libANGLE/Framebuffer.h b/src/3rdparty/angle/src/libANGLE/Framebuffer.h
index 8b24cf984e..b07b59ac90 100644
--- a/src/3rdparty/angle/src/libANGLE/Framebuffer.h
+++ b/src/3rdparty/angle/src/libANGLE/Framebuffer.h
@@ -14,7 +14,9 @@
#include "common/angleutils.h"
#include "libANGLE/Constants.h"
+#include "libANGLE/Debug.h"
#include "libANGLE/Error.h"
+#include "libANGLE/FramebufferAttachment.h"
#include "libANGLE/RefCountObject.h"
namespace rx
@@ -22,7 +24,7 @@ namespace rx
class ImplFactory;
class FramebufferImpl;
class RenderbufferImpl;
-struct Workarounds;
+class SurfaceImpl;
}
namespace egl
@@ -32,7 +34,7 @@ class Surface;
namespace gl
{
-class FramebufferAttachment;
+class Context;
class Renderbuffer;
class State;
class Texture;
@@ -43,64 +45,89 @@ struct Extensions;
struct ImageIndex;
struct Rectangle;
-typedef std::vector<FramebufferAttachment *> AttachmentList;
-
-class Framebuffer
+class Framebuffer final : public LabeledObject
{
public:
class Data final : angle::NonCopyable
{
public:
+ explicit Data();
explicit Data(const Caps &caps);
~Data();
- FramebufferAttachment *getReadAttachment() const;
- FramebufferAttachment *getFirstColorAttachment() const;
- FramebufferAttachment *getDepthOrStencilAttachment() const;
+ const std::string &getLabel();
+
+ const FramebufferAttachment *getReadAttachment() const;
+ const FramebufferAttachment *getFirstColorAttachment() const;
+ const FramebufferAttachment *getDepthOrStencilAttachment() const;
+ const FramebufferAttachment *getColorAttachment(size_t colorAttachment) const;
+ const FramebufferAttachment *getDepthAttachment() const;
+ const FramebufferAttachment *getStencilAttachment() const;
+ const FramebufferAttachment *getDepthStencilAttachment() const;
+
+ const std::vector<GLenum> &getDrawBufferStates() const { return mDrawBufferStates; }
+ GLenum getReadBufferState() const { return mReadBufferState; }
+ const std::vector<FramebufferAttachment> &getColorAttachments() const { return mColorAttachments; }
+
+ bool attachmentsHaveSameDimensions() const;
- AttachmentList mColorAttachments;
- FramebufferAttachment *mDepthAttachment;
- FramebufferAttachment *mStencilAttachment;
+ private:
+ friend class Framebuffer;
+
+ std::string mLabel;
+
+ std::vector<FramebufferAttachment> mColorAttachments;
+ FramebufferAttachment mDepthAttachment;
+ FramebufferAttachment mStencilAttachment;
std::vector<GLenum> mDrawBufferStates;
GLenum mReadBufferState;
};
Framebuffer(const Caps &caps, rx::ImplFactory *factory, GLuint id);
+ Framebuffer(rx::SurfaceImpl *surface);
virtual ~Framebuffer();
+ void setLabel(const std::string &label) override;
+ const std::string &getLabel() const override;
+
const rx::FramebufferImpl *getImplementation() const { return mImpl; }
rx::FramebufferImpl *getImplementation() { return mImpl; }
GLuint id() const { return mId; }
- void setTextureAttachment(GLenum attachment, Texture *texture, const ImageIndex &imageIndex);
- void setRenderbufferAttachment(GLenum attachment, Renderbuffer *renderbuffer);
- void setNULLAttachment(GLenum attachment);
+ void setAttachment(GLenum type,
+ GLenum binding,
+ const ImageIndex &textureIndex,
+ FramebufferAttachmentObject *resource);
+ void resetAttachment(GLenum binding);
void detachTexture(GLuint texture);
void detachRenderbuffer(GLuint renderbuffer);
- FramebufferAttachment *getColorbuffer(unsigned int colorAttachment) const;
- FramebufferAttachment *getDepthbuffer() const;
- FramebufferAttachment *getStencilbuffer() const;
- FramebufferAttachment *getDepthStencilBuffer() const;
- FramebufferAttachment *getDepthOrStencilbuffer() const;
- FramebufferAttachment *getReadColorbuffer() const;
+ const FramebufferAttachment *getColorbuffer(size_t colorAttachment) const;
+ const FramebufferAttachment *getDepthbuffer() const;
+ const FramebufferAttachment *getStencilbuffer() const;
+ const FramebufferAttachment *getDepthStencilBuffer() const;
+ const FramebufferAttachment *getDepthOrStencilbuffer() const;
+ const FramebufferAttachment *getReadColorbuffer() const;
GLenum getReadColorbufferType() const;
- FramebufferAttachment *getFirstColorbuffer() const;
+ const FramebufferAttachment *getFirstColorbuffer() const;
- FramebufferAttachment *getAttachment(GLenum attachment) const;
+ const FramebufferAttachment *getAttachment(GLenum attachment) const;
- GLenum getDrawBufferState(unsigned int colorAttachment) const;
+ size_t getDrawbufferStateCount() const;
+ GLenum getDrawBufferState(size_t drawBuffer) const;
void setDrawBuffers(size_t count, const GLenum *buffers);
+ const FramebufferAttachment *getDrawBuffer(size_t drawBuffer) const;
+ bool hasEnabledDrawBuffer() const;
GLenum getReadBufferState() const;
void setReadBuffer(GLenum buffer);
- bool isEnabledColorAttachment(unsigned int colorAttachment) const;
- bool hasEnabledColorAttachment() const;
+ size_t getNumColorBuffers() const;
+ bool hasDepth() const;
bool hasStencil() const;
int getSamples(const gl::Data &data) const;
bool usingExtendedDrawBuffers() const;
@@ -108,35 +135,68 @@ class Framebuffer
GLenum checkStatus(const gl::Data &data) const;
bool hasValidDepthStencil() const;
+ Error discard(size_t count, const GLenum *attachments);
Error invalidate(size_t count, const GLenum *attachments);
Error invalidateSub(size_t count, const GLenum *attachments, const gl::Rectangle &area);
Error clear(const gl::Data &data, GLbitfield mask);
- Error clearBufferfv(const State &state, GLenum buffer, GLint drawbuffer, const GLfloat *values);
- Error clearBufferuiv(const State &state, GLenum buffer, GLint drawbuffer, const GLuint *values);
- Error clearBufferiv(const State &state, GLenum buffer, GLint drawbuffer, const GLint *values);
- Error clearBufferfi(const State &state, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);
+ Error clearBufferfv(const gl::Data &data,
+ GLenum buffer,
+ GLint drawbuffer,
+ const GLfloat *values);
+ Error clearBufferuiv(const gl::Data &data,
+ GLenum buffer,
+ GLint drawbuffer,
+ const GLuint *values);
+ Error clearBufferiv(const gl::Data &data, GLenum buffer, GLint drawbuffer, const GLint *values);
+ Error clearBufferfi(const gl::Data &data,
+ GLenum buffer,
+ GLint drawbuffer,
+ GLfloat depth,
+ GLint stencil);
GLenum getImplementationColorReadFormat() const;
GLenum getImplementationColorReadType() const;
- Error readPixels(const gl::State &state, const gl::Rectangle &area, GLenum format, GLenum type, GLvoid *pixels) const;
+ Error readPixels(const gl::State &state,
+ const gl::Rectangle &area,
+ GLenum format,
+ GLenum type,
+ GLvoid *pixels) const;
+
+ Error blit(const State &state,
+ const Rectangle &sourceArea,
+ const Rectangle &destArea,
+ GLbitfield mask,
+ GLenum filter,
+ const Framebuffer *sourceFramebuffer);
+
+ enum DirtyBitType
+ {
+ DIRTY_BIT_COLOR_ATTACHMENT_0,
+ DIRTY_BIT_COLOR_ATTACHMENT_MAX =
+ DIRTY_BIT_COLOR_ATTACHMENT_0 + gl::IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS,
+ DIRTY_BIT_DEPTH_ATTACHMENT = DIRTY_BIT_COLOR_ATTACHMENT_MAX,
+ DIRTY_BIT_STENCIL_ATTACHMENT,
+ DIRTY_BIT_DRAW_BUFFERS,
+ DIRTY_BIT_READ_BUFFER,
+ DIRTY_BIT_UNKNOWN,
+ DIRTY_BIT_MAX = DIRTY_BIT_UNKNOWN,
+ };
+
+ typedef std::bitset<DIRTY_BIT_MAX> DirtyBits;
+ bool hasAnyDirtyBit() const { return mDirtyBits.any(); }
- Error blit(const gl::State &state, const gl::Rectangle &sourceArea, const gl::Rectangle &destArea,
- GLbitfield mask, GLenum filter, const gl::Framebuffer *sourceFramebuffer);
+ void syncState() const;
protected:
- void setAttachment(GLenum attachment, FramebufferAttachment *attachmentObj);
void detachResourceById(GLenum resourceType, GLuint resourceId);
Data mData;
rx::FramebufferImpl *mImpl;
GLuint mId;
-};
-class DefaultFramebuffer : public Framebuffer
-{
- public:
- DefaultFramebuffer(const gl::Caps &caps, rx::ImplFactory *factory, egl::Surface *surface);
+ // TODO(jmadill): See if we can make this non-mutable.
+ mutable DirtyBits mDirtyBits;
};
}
diff --git a/src/3rdparty/angle/src/libANGLE/FramebufferAttachment.cpp b/src/3rdparty/angle/src/libANGLE/FramebufferAttachment.cpp
index e56fc750ad..352a326c23 100644
--- a/src/3rdparty/angle/src/libANGLE/FramebufferAttachment.cpp
+++ b/src/3rdparty/angle/src/libANGLE/FramebufferAttachment.cpp
@@ -20,283 +20,189 @@
namespace gl
{
-////// FramebufferAttachment Implementation //////
+////// FramebufferAttachment::Target Implementation //////
-FramebufferAttachment::FramebufferAttachment(GLenum binding)
- : mBinding(binding)
+FramebufferAttachment::Target::Target()
+ : mBinding(GL_NONE),
+ mTextureIndex(ImageIndex::MakeInvalid())
{
}
-FramebufferAttachment::~FramebufferAttachment()
+FramebufferAttachment::Target::Target(GLenum binding, const ImageIndex &imageIndex)
+ : mBinding(binding),
+ mTextureIndex(imageIndex)
{
}
-GLuint FramebufferAttachment::getRedSize() const
+FramebufferAttachment::Target::Target(const Target &other)
+ : mBinding(other.mBinding),
+ mTextureIndex(other.mTextureIndex)
{
- return GetInternalFormatInfo(getInternalFormat()).redBits;
}
-GLuint FramebufferAttachment::getGreenSize() const
+FramebufferAttachment::Target &FramebufferAttachment::Target::operator=(const Target &other)
{
- return GetInternalFormatInfo(getInternalFormat()).greenBits;
+ this->mBinding = other.mBinding;
+ this->mTextureIndex = other.mTextureIndex;
+ return *this;
}
-GLuint FramebufferAttachment::getBlueSize() const
-{
- return GetInternalFormatInfo(getInternalFormat()).blueBits;
-}
-
-GLuint FramebufferAttachment::getAlphaSize() const
-{
- return GetInternalFormatInfo(getInternalFormat()).alphaBits;
-}
-
-GLuint FramebufferAttachment::getDepthSize() const
-{
- return GetInternalFormatInfo(getInternalFormat()).depthBits;
-}
-
-GLuint FramebufferAttachment::getStencilSize() const
-{
- return GetInternalFormatInfo(getInternalFormat()).stencilBits;
-}
-
-GLenum FramebufferAttachment::getComponentType() const
-{
- return GetInternalFormatInfo(getInternalFormat()).componentType;
-}
-
-GLenum FramebufferAttachment::getColorEncoding() const
-{
- return GetInternalFormatInfo(getInternalFormat()).colorEncoding;
-}
-
-///// TextureAttachment Implementation ////////
-
-TextureAttachment::TextureAttachment(GLenum binding, Texture *texture, const ImageIndex &index)
- : FramebufferAttachment(binding),
- mIndex(index)
-{
- mTexture.set(texture);
-}
-
-TextureAttachment::~TextureAttachment()
-{
- mTexture.set(NULL);
-}
-
-GLsizei TextureAttachment::getSamples() const
-{
- return 0;
-}
-
-GLuint TextureAttachment::id() const
-{
- return mTexture->id();
-}
-
-GLsizei TextureAttachment::getWidth() const
-{
- return mTexture->getWidth(mIndex.type, mIndex.mipIndex);
-}
-
-GLsizei TextureAttachment::getHeight() const
-{
- return mTexture->getHeight(mIndex.type, mIndex.mipIndex);
-}
-
-GLenum TextureAttachment::getInternalFormat() const
-{
- return mTexture->getInternalFormat(mIndex.type, mIndex.mipIndex);
-}
-
-GLenum TextureAttachment::type() const
-{
- return GL_TEXTURE;
-}
-
-GLint TextureAttachment::mipLevel() const
-{
- return mIndex.mipIndex;
-}
-
-GLenum TextureAttachment::cubeMapFace() const
-{
- return IsCubeMapTextureTarget(mIndex.type) ? mIndex.type : GL_NONE;
-}
-
-GLint TextureAttachment::layer() const
-{
- return mIndex.layerIndex;
-}
-
-Texture *TextureAttachment::getTexture() const
-{
- return mTexture.get();
-}
-
-const ImageIndex *TextureAttachment::getTextureImageIndex() const
-{
- return &mIndex;
-}
-
-Renderbuffer *TextureAttachment::getRenderbuffer() const
-{
- UNREACHABLE();
- return NULL;
-}
-
-////// RenderbufferAttachment Implementation //////
+////// FramebufferAttachment Implementation //////
-RenderbufferAttachment::RenderbufferAttachment(GLenum binding, Renderbuffer *renderbuffer)
- : FramebufferAttachment(binding)
+FramebufferAttachment::FramebufferAttachment()
+ : mType(GL_NONE), mResource(nullptr)
{
- ASSERT(renderbuffer);
- mRenderbuffer.set(renderbuffer);
}
-RenderbufferAttachment::~RenderbufferAttachment()
+FramebufferAttachment::FramebufferAttachment(GLenum type,
+ GLenum binding,
+ const ImageIndex &textureIndex,
+ FramebufferAttachmentObject *resource)
+ : mResource(nullptr)
{
- mRenderbuffer.set(NULL);
+ attach(type, binding, textureIndex, resource);
}
-GLsizei RenderbufferAttachment::getWidth() const
+FramebufferAttachment::FramebufferAttachment(const FramebufferAttachment &other)
+ : mResource(nullptr)
{
- return mRenderbuffer->getWidth();
+ attach(other.mType, other.mTarget.binding(), other.mTarget.textureIndex(), other.mResource);
}
-GLsizei RenderbufferAttachment::getHeight() const
+FramebufferAttachment &FramebufferAttachment::operator=(const FramebufferAttachment &other)
{
- return mRenderbuffer->getHeight();
+ attach(other.mType, other.mTarget.binding(), other.mTarget.textureIndex(), other.mResource);
+ return *this;
}
-GLenum RenderbufferAttachment::getInternalFormat() const
+FramebufferAttachment::~FramebufferAttachment()
{
- return mRenderbuffer->getInternalFormat();
+ detach();
}
-GLsizei RenderbufferAttachment::getSamples() const
+void FramebufferAttachment::detach()
{
- return mRenderbuffer->getSamples();
-}
+ mType = GL_NONE;
+ if (mResource != nullptr)
+ {
+ mResource->onDetach();
+ mResource = nullptr;
+ }
-GLuint RenderbufferAttachment::id() const
-{
- return mRenderbuffer->id();
+ // not technically necessary, could omit for performance
+ mTarget = Target();
}
-GLenum RenderbufferAttachment::type() const
+void FramebufferAttachment::attach(GLenum type,
+ GLenum binding,
+ const ImageIndex &textureIndex,
+ FramebufferAttachmentObject *resource)
{
- return GL_RENDERBUFFER;
-}
+ mType = type;
+ mTarget = Target(binding, textureIndex);
-GLint RenderbufferAttachment::mipLevel() const
-{
- return 0;
+ if (resource)
+ {
+ resource->onAttach();
+ }
+ if (mResource != nullptr)
+ {
+ mResource->onDetach();
+ }
+ mResource = resource;
}
-GLenum RenderbufferAttachment::cubeMapFace() const
+GLuint FramebufferAttachment::getRedSize() const
{
- return GL_NONE;
+ return GetInternalFormatInfo(getInternalFormat()).redBits;
}
-GLint RenderbufferAttachment::layer() const
+GLuint FramebufferAttachment::getGreenSize() const
{
- return 0;
+ return GetInternalFormatInfo(getInternalFormat()).greenBits;
}
-Texture *RenderbufferAttachment::getTexture() const
+GLuint FramebufferAttachment::getBlueSize() const
{
- UNREACHABLE();
- return NULL;
+ return GetInternalFormatInfo(getInternalFormat()).blueBits;
}
-const ImageIndex *RenderbufferAttachment::getTextureImageIndex() const
+GLuint FramebufferAttachment::getAlphaSize() const
{
- UNREACHABLE();
- return NULL;
+ return GetInternalFormatInfo(getInternalFormat()).alphaBits;
}
-Renderbuffer *RenderbufferAttachment::getRenderbuffer() const
+GLuint FramebufferAttachment::getDepthSize() const
{
- return mRenderbuffer.get();
+ return GetInternalFormatInfo(getInternalFormat()).depthBits;
}
-
-DefaultAttachment::DefaultAttachment(GLenum binding, egl::Surface *surface)
- : FramebufferAttachment(binding)
+GLuint FramebufferAttachment::getStencilSize() const
{
- mSurface.set(surface);
+ return GetInternalFormatInfo(getInternalFormat()).stencilBits;
}
-DefaultAttachment::~DefaultAttachment()
+GLenum FramebufferAttachment::getComponentType() const
{
- mSurface.set(nullptr);
+ return GetInternalFormatInfo(getInternalFormat()).componentType;
}
-GLsizei DefaultAttachment::getWidth() const
+GLenum FramebufferAttachment::getColorEncoding() const
{
- return mSurface->getWidth();
+ return GetInternalFormatInfo(getInternalFormat()).colorEncoding;
}
-GLsizei DefaultAttachment::getHeight() const
+GLuint FramebufferAttachment::id() const
{
- return mSurface->getHeight();
+ return mResource->getId();
}
-GLenum DefaultAttachment::getInternalFormat() const
+const ImageIndex &FramebufferAttachment::getTextureImageIndex() const
{
- const egl::Config *config = mSurface->getConfig();
- return (getBinding() == GL_BACK ? config->renderTargetFormat : config->depthStencilFormat);
+ ASSERT(type() == GL_TEXTURE);
+ return mTarget.textureIndex();
}
-GLsizei DefaultAttachment::getSamples() const
+GLenum FramebufferAttachment::cubeMapFace() const
{
- const egl::Config *config = mSurface->getConfig();
- return config->samples;
-}
+ ASSERT(mType == GL_TEXTURE);
-GLuint DefaultAttachment::id() const
-{
- return 0;
+ const auto &index = mTarget.textureIndex();
+ return IsCubeMapTextureTarget(index.type) ? index.type : GL_NONE;
}
-GLenum DefaultAttachment::type() const
+GLint FramebufferAttachment::mipLevel() const
{
- return GL_FRAMEBUFFER_DEFAULT;
+ ASSERT(type() == GL_TEXTURE);
+ return mTarget.textureIndex().mipIndex;
}
-GLint DefaultAttachment::mipLevel() const
+GLint FramebufferAttachment::layer() const
{
- return 0;
-}
+ ASSERT(mType == GL_TEXTURE);
-GLenum DefaultAttachment::cubeMapFace() const
-{
- return GL_NONE;
-}
+ const auto &index = mTarget.textureIndex();
-GLint DefaultAttachment::layer() const
-{
+ if (index.type == GL_TEXTURE_2D_ARRAY || index.type == GL_TEXTURE_3D)
+ {
+ return index.layerIndex;
+ }
return 0;
}
-Texture *DefaultAttachment::getTexture() const
+Texture *FramebufferAttachment::getTexture() const
{
- UNREACHABLE();
- return NULL;
+ return rx::GetAs<Texture>(mResource);
}
-const ImageIndex *DefaultAttachment::getTextureImageIndex() const
+Renderbuffer *FramebufferAttachment::getRenderbuffer() const
{
- UNREACHABLE();
- return NULL;
+ return rx::GetAs<Renderbuffer>(mResource);
}
-Renderbuffer *DefaultAttachment::getRenderbuffer() const
+const egl::Surface *FramebufferAttachment::getSurface() const
{
- UNREACHABLE();
- return NULL;
+ return rx::GetAs<egl::Surface>(mResource);
}
}
diff --git a/src/3rdparty/angle/src/libANGLE/FramebufferAttachment.h b/src/3rdparty/angle/src/libANGLE/FramebufferAttachment.h
index 0662130931..33196f5c61 100644
--- a/src/3rdparty/angle/src/libANGLE/FramebufferAttachment.h
+++ b/src/3rdparty/angle/src/libANGLE/FramebufferAttachment.h
@@ -10,16 +10,36 @@
#ifndef LIBANGLE_FRAMEBUFFERATTACHMENT_H_
#define LIBANGLE_FRAMEBUFFERATTACHMENT_H_
-#include "libANGLE/Texture.h"
-#include "libANGLE/RefCountObject.h"
-
+#include "angle_gl.h"
#include "common/angleutils.h"
+#include "libANGLE/angletypes.h"
+#include "libANGLE/Error.h"
+#include "libANGLE/ImageIndex.h"
-#include "angle_gl.h"
+namespace egl
+{
+class Surface;
+}
+
+namespace rx
+{
+// An implementation-specific object associated with an attachment.
+
+class FramebufferAttachmentRenderTarget : angle::NonCopyable
+{
+ public:
+ FramebufferAttachmentRenderTarget() {}
+ virtual ~FramebufferAttachmentRenderTarget() {}
+};
+
+class FramebufferAttachmentObjectImpl;
+}
namespace gl
{
+class FramebufferAttachmentObject;
class Renderbuffer;
+class Texture;
// FramebufferAttachment implements a GL framebuffer attachment.
// Attachments are "light" containers, which store pointers to ref-counted GL objects.
@@ -27,11 +47,48 @@ class Renderbuffer;
// Note: Our old naming scheme used the term "Renderbuffer" for both GL renderbuffers and for
// framebuffer attachments, which confused their usage.
-class FramebufferAttachment : angle::NonCopyable
+class FramebufferAttachment final
{
public:
- explicit FramebufferAttachment(GLenum binding);
- virtual ~FramebufferAttachment();
+ FramebufferAttachment();
+
+ FramebufferAttachment(GLenum type,
+ GLenum binding,
+ const ImageIndex &textureIndex,
+ FramebufferAttachmentObject *resource);
+
+ FramebufferAttachment(const FramebufferAttachment &other);
+ FramebufferAttachment &operator=(const FramebufferAttachment &other);
+
+ ~FramebufferAttachment();
+
+ // A framebuffer attachment points to one of three types of resources: Renderbuffers,
+ // Textures and egl::Surface. The "Target" struct indicates which part of the
+ // object an attachment references. For the three types:
+ // - a Renderbuffer has a unique renderable target, and needs no target index
+ // - a Texture has targets for every image and uses an ImageIndex
+ // - a Surface has targets for Color and Depth/Stencil, and uses the attachment binding
+ class Target
+ {
+ public:
+ Target();
+ Target(GLenum binding, const ImageIndex &imageIndex);
+ Target(const Target &other);
+ Target &operator=(const Target &other);
+
+ GLenum binding() const { return mBinding; }
+ const ImageIndex &textureIndex() const { return mTextureIndex; }
+
+ private:
+ GLenum mBinding;
+ ImageIndex mTextureIndex;
+ };
+
+ void detach();
+ void attach(GLenum type,
+ GLenum binding,
+ const ImageIndex &textureIndex,
+ FramebufferAttachmentObject *resource);
// Helper methods
GLuint getRedSize() const;
@@ -43,111 +100,118 @@ class FramebufferAttachment : angle::NonCopyable
GLenum getComponentType() const;
GLenum getColorEncoding() const;
- bool isTextureWithId(GLuint textureId) const { return type() == GL_TEXTURE && id() == textureId; }
- bool isRenderbufferWithId(GLuint renderbufferId) const { return type() == GL_RENDERBUFFER && id() == renderbufferId; }
-
- GLenum getBinding() const { return mBinding; }
-
- // Child class interface
- virtual GLsizei getWidth() const = 0;
- virtual GLsizei getHeight() const = 0;
- virtual GLenum getInternalFormat() const = 0;
- virtual GLsizei getSamples() const = 0;
-
- virtual GLuint id() const = 0;
- virtual GLenum type() const = 0;
- virtual GLint mipLevel() const = 0;
- virtual GLenum cubeMapFace() const = 0;
- virtual GLint layer() const = 0;
-
- virtual Texture *getTexture() const = 0;
- virtual const ImageIndex *getTextureImageIndex() const = 0;
- virtual Renderbuffer *getRenderbuffer() const = 0;
+ bool isTextureWithId(GLuint textureId) const { return mType == GL_TEXTURE && id() == textureId; }
+ bool isRenderbufferWithId(GLuint renderbufferId) const { return mType == GL_RENDERBUFFER && id() == renderbufferId; }
+
+ GLenum getBinding() const { return mTarget.binding(); }
+ GLuint id() const;
+
+ // These methods are only legal to call on Texture attachments
+ const ImageIndex &getTextureImageIndex() const;
+ GLenum cubeMapFace() const;
+ GLint mipLevel() const;
+ GLint layer() const;
+
+ // The size of the underlying resource the attachment points to. The 'depth' value will
+ // correspond to a 3D texture depth or the layer count of a 2D array texture. For Surfaces and
+ // Renderbuffers, it will always be 1.
+ Extents getSize() const;
+ GLenum getInternalFormat() const;
+ GLsizei getSamples() const;
+ GLenum type() const { return mType; }
+ bool isAttached() const { return mType != GL_NONE; }
+
+ Renderbuffer *getRenderbuffer() const;
+ Texture *getTexture() const;
+ const egl::Surface *getSurface() const;
+
+ // "T" must be static_castable from FramebufferAttachmentRenderTarget
+ template <typename T>
+ gl::Error getRenderTarget(T **rtOut) const
+ {
+ // Cast through the pointer-to-pointer type
+ rx::FramebufferAttachmentRenderTarget *rtPtr = nullptr;
+ gl::Error error = getRenderTarget(&rtPtr);
+ *rtOut = static_cast<T*>(rtPtr);
+ return error;
+ }
private:
- GLenum mBinding;
+ gl::Error getRenderTarget(rx::FramebufferAttachmentRenderTarget **rtOut) const;
+
+ GLenum mType;
+ Target mTarget;
+ FramebufferAttachmentObject *mResource;
};
-class TextureAttachment : public FramebufferAttachment
+// A base class for objects that FBO Attachments may point to.
+class FramebufferAttachmentObject
{
public:
- TextureAttachment(GLenum binding, Texture *texture, const ImageIndex &index);
- virtual ~TextureAttachment();
+ FramebufferAttachmentObject() {}
+ virtual ~FramebufferAttachmentObject() {}
- virtual GLsizei getSamples() const;
- virtual GLuint id() const;
+ virtual Extents getAttachmentSize(const FramebufferAttachment::Target &target) const = 0;
+ virtual GLenum getAttachmentInternalFormat(const FramebufferAttachment::Target &target) const = 0;
+ virtual GLsizei getAttachmentSamples(const FramebufferAttachment::Target &target) const = 0;
- virtual GLsizei getWidth() const;
- virtual GLsizei getHeight() const;
- virtual GLenum getInternalFormat() const;
+ virtual void onAttach() = 0;
+ virtual void onDetach() = 0;
+ virtual GLuint getId() const = 0;
- virtual GLenum type() const;
- virtual GLint mipLevel() const;
- virtual GLenum cubeMapFace() const;
- virtual GLint layer() const;
+ Error getAttachmentRenderTarget(const FramebufferAttachment::Target &target,
+ rx::FramebufferAttachmentRenderTarget **rtOut) const;
- virtual Texture *getTexture() const;
- virtual const ImageIndex *getTextureImageIndex() const;
- virtual Renderbuffer *getRenderbuffer() const;
-
- private:
- BindingPointer<Texture> mTexture;
- ImageIndex mIndex;
+ protected:
+ virtual rx::FramebufferAttachmentObjectImpl *getAttachmentImpl() const = 0;
};
-class RenderbufferAttachment : public FramebufferAttachment
+inline Extents FramebufferAttachment::getSize() const
{
- public:
- RenderbufferAttachment(GLenum binding, Renderbuffer *renderbuffer);
+ return mResource->getAttachmentSize(mTarget);
+}
- virtual ~RenderbufferAttachment();
+inline GLenum FramebufferAttachment::getInternalFormat() const
+{
+ return mResource->getAttachmentInternalFormat(mTarget);
+}
- virtual GLsizei getWidth() const;
- virtual GLsizei getHeight() const;
- virtual GLenum getInternalFormat() const;
- virtual GLsizei getSamples() const;
+inline GLsizei FramebufferAttachment::getSamples() const
+{
+ return mResource->getAttachmentSamples(mTarget);
+}
- virtual GLuint id() const;
- virtual GLenum type() const;
- virtual GLint mipLevel() const;
- virtual GLenum cubeMapFace() const;
- virtual GLint layer() const;
+inline gl::Error FramebufferAttachment::getRenderTarget(rx::FramebufferAttachmentRenderTarget **rtOut) const
+{
+ return mResource->getAttachmentRenderTarget(mTarget, rtOut);
+}
- virtual Texture *getTexture() const;
- virtual const ImageIndex *getTextureImageIndex() const;
- virtual Renderbuffer *getRenderbuffer() const;
+} // namespace gl
- private:
- BindingPointer<Renderbuffer> mRenderbuffer;
-};
+namespace rx
+{
-class DefaultAttachment : public FramebufferAttachment
+class FramebufferAttachmentObjectImpl : angle::NonCopyable
{
public:
- DefaultAttachment(GLenum binding, egl::Surface *surface);
-
- virtual ~DefaultAttachment();
-
- virtual GLsizei getWidth() const;
- virtual GLsizei getHeight() const;
- virtual GLenum getInternalFormat() const;
- virtual GLsizei getSamples() const;
+ FramebufferAttachmentObjectImpl() {}
+ virtual ~FramebufferAttachmentObjectImpl() {}
- virtual GLuint id() const;
- virtual GLenum type() const;
- virtual GLint mipLevel() const;
- virtual GLenum cubeMapFace() const;
- virtual GLint layer() const;
+ virtual gl::Error getAttachmentRenderTarget(const gl::FramebufferAttachment::Target &target,
+ FramebufferAttachmentRenderTarget **rtOut) = 0;
+};
- virtual Texture *getTexture() const;
- virtual const ImageIndex *getTextureImageIndex() const;
- virtual Renderbuffer *getRenderbuffer() const;
+} // namespace rx
- const egl::Surface *getSurface() const { return mSurface.get(); }
+namespace gl
+{
- private:
- BindingPointer<egl::Surface> mSurface;
-};
+inline Error FramebufferAttachmentObject::getAttachmentRenderTarget(
+ const FramebufferAttachment::Target &target,
+ rx::FramebufferAttachmentRenderTarget **rtOut) const
+{
+ return getAttachmentImpl()->getAttachmentRenderTarget(target, rtOut);
+}
}
diff --git a/src/3rdparty/angle/src/libANGLE/HandleAllocator.cpp b/src/3rdparty/angle/src/libANGLE/HandleAllocator.cpp
index 59d3966758..4815855d5a 100644
--- a/src/3rdparty/angle/src/libANGLE/HandleAllocator.cpp
+++ b/src/3rdparty/angle/src/libANGLE/HandleAllocator.cpp
@@ -20,13 +20,13 @@ struct HandleAllocator::HandleRangeComparator
{
bool operator()(const HandleRange &range, GLuint handle) const
{
- return (handle < range.begin);
+ return (range.end < handle);
}
};
HandleAllocator::HandleAllocator() : mBaseValue(1), mNextValue(1)
{
- mUnallocatedList.push_back(HandleRange(1, std::numeric_limits<GLuint>::max() - 1));
+ mUnallocatedList.push_back(HandleRange(1, std::numeric_limits<GLuint>::max()));
}
HandleAllocator::HandleAllocator(GLuint maximumHandleValue) : mBaseValue(1), mNextValue(1)
@@ -120,14 +120,15 @@ void HandleAllocator::reserve(GLuint handle)
// need to split the range
auto placementIt = mUnallocatedList.erase(boundIt);
- if (begin != handle)
+ if (handle + 1 != end)
{
- placementIt = mUnallocatedList.insert(placementIt, HandleRange(begin, handle));
+ placementIt = mUnallocatedList.insert(placementIt, HandleRange(handle + 1, end));
}
- if (handle + 1 != end)
+ if (begin != handle)
{
- mUnallocatedList.insert(placementIt, HandleRange(handle + 1, end));
+ ASSERT(begin < handle);
+ mUnallocatedList.insert(placementIt, HandleRange(begin, handle));
}
}
-}
+} // namespace gl
diff --git a/src/3rdparty/angle/src/libANGLE/HandleAllocator.h b/src/3rdparty/angle/src/libANGLE/HandleAllocator.h
index c22f2ba61a..1888d57cfa 100644
--- a/src/3rdparty/angle/src/libANGLE/HandleAllocator.h
+++ b/src/3rdparty/angle/src/libANGLE/HandleAllocator.h
@@ -58,6 +58,6 @@ class HandleAllocator final : angle::NonCopyable
std::vector<GLuint> mReleasedList;
};
-}
+} // namespace gl
#endif // LIBANGLE_HANDLEALLOCATOR_H_
diff --git a/src/3rdparty/angle/src/libANGLE/Image.cpp b/src/3rdparty/angle/src/libANGLE/Image.cpp
new file mode 100644
index 0000000000..a9448e3f6c
--- /dev/null
+++ b/src/3rdparty/angle/src/libANGLE/Image.cpp
@@ -0,0 +1,192 @@
+//
+// 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.
+//
+
+// Image.cpp: Implements the egl::Image class representing the EGLimage object.
+
+#include "libANGLE/Image.h"
+
+#include "common/debug.h"
+#include "common/utilities.h"
+#include "libANGLE/angletypes.h"
+#include "libANGLE/Texture.h"
+#include "libANGLE/Renderbuffer.h"
+#include "libANGLE/renderer/ImageImpl.h"
+
+namespace egl
+{
+ImageSibling::ImageSibling(GLuint id) : RefCountObject(id), mSourcesOf(), mTargetOf()
+{
+}
+
+ImageSibling::~ImageSibling()
+{
+ // EGL images should hold a ref to their targets and siblings, a Texture should not be deletable
+ // while it is attached to an EGL image.
+ ASSERT(mSourcesOf.empty());
+ orphanImages();
+}
+
+void ImageSibling::setTargetImage(egl::Image *imageTarget)
+{
+ ASSERT(imageTarget != nullptr);
+ mTargetOf.set(imageTarget);
+ imageTarget->addTargetSibling(this);
+}
+
+gl::Error ImageSibling::orphanImages()
+{
+ if (mTargetOf.get() != nullptr)
+ {
+ // Can't be a target and have sources.
+ ASSERT(mSourcesOf.empty());
+
+ gl::Error error = mTargetOf->orphanSibling(this);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ mTargetOf.set(nullptr);
+ }
+ else
+ {
+ for (auto &sourceImage : mSourcesOf)
+ {
+ gl::Error error = sourceImage->orphanSibling(this);
+ if (error.isError())
+ {
+ return error;
+ }
+ }
+ mSourcesOf.clear();
+ }
+
+ return gl::Error(GL_NO_ERROR);
+}
+
+void ImageSibling::addImageSource(egl::Image *imageSource)
+{
+ ASSERT(imageSource != nullptr);
+ mSourcesOf.insert(imageSource);
+}
+
+void ImageSibling::removeImageSource(egl::Image *imageSource)
+{
+ ASSERT(mSourcesOf.find(imageSource) != mSourcesOf.end());
+ mSourcesOf.erase(imageSource);
+}
+
+Image::Image(rx::ImageImpl *impl, EGLenum target, ImageSibling *buffer, const AttributeMap &attribs)
+ : RefCountObject(0),
+ mImplementation(impl),
+ mInternalFormat(GL_NONE),
+ mWidth(0),
+ mHeight(0),
+ mSamples(0),
+ mSource(),
+ mTargets()
+{
+ ASSERT(mImplementation != nullptr);
+ ASSERT(buffer != nullptr);
+
+ mSource.set(buffer);
+ mSource->addImageSource(this);
+
+ if (IsTextureTarget(target))
+ {
+ gl::Texture *texture = rx::GetAs<gl::Texture>(mSource.get());
+ GLenum textureTarget = egl_gl::EGLImageTargetToGLTextureTarget(target);
+ size_t level = attribs.get(EGL_GL_TEXTURE_LEVEL_KHR, 0);
+ mInternalFormat = texture->getInternalFormat(textureTarget, level);
+ mWidth = texture->getWidth(textureTarget, level);
+ mHeight = texture->getHeight(textureTarget, level);
+ mSamples = 0;
+ }
+ else if (IsRenderbufferTarget(target))
+ {
+ gl::Renderbuffer *renderbuffer = rx::GetAs<gl::Renderbuffer>(mSource.get());
+ mInternalFormat = renderbuffer->getInternalFormat();
+ mWidth = renderbuffer->getWidth();
+ mHeight = renderbuffer->getHeight();
+ mSamples = renderbuffer->getSamples();
+ }
+ else
+ {
+ UNREACHABLE();
+ }
+}
+
+Image::~Image()
+{
+ SafeDelete(mImplementation);
+
+ // All targets should hold a ref to the egl image and it should not be deleted until there are
+ // no siblings left.
+ ASSERT(mTargets.empty());
+
+ // Tell the source that it is no longer used by this image
+ if (mSource.get() != nullptr)
+ {
+ mSource->removeImageSource(this);
+ mSource.set(nullptr);
+ }
+}
+
+void Image::addTargetSibling(ImageSibling *sibling)
+{
+ mTargets.insert(sibling);
+}
+
+gl::Error Image::orphanSibling(ImageSibling *sibling)
+{
+ // notify impl
+ gl::Error error = mImplementation->orphan(sibling);
+
+ if (mSource.get() == sibling)
+ {
+ // If the sibling is the source, it cannot be a target.
+ ASSERT(mTargets.find(sibling) == mTargets.end());
+
+ mSource.set(nullptr);
+ }
+ else
+ {
+ mTargets.erase(sibling);
+ }
+
+ return error;
+}
+
+GLenum Image::getInternalFormat() const
+{
+ return mInternalFormat;
+}
+
+size_t Image::getWidth() const
+{
+ return mWidth;
+}
+
+size_t Image::getHeight() const
+{
+ return mHeight;
+}
+
+size_t Image::getSamples() const
+{
+ return mSamples;
+}
+
+rx::ImageImpl *Image::getImplementation()
+{
+ return mImplementation;
+}
+
+const rx::ImageImpl *Image::getImplementation() const
+{
+ return mImplementation;
+}
+}
diff --git a/src/3rdparty/angle/src/libANGLE/Image.h b/src/3rdparty/angle/src/libANGLE/Image.h
new file mode 100644
index 0000000000..26c9df914c
--- /dev/null
+++ b/src/3rdparty/angle/src/libANGLE/Image.h
@@ -0,0 +1,91 @@
+//
+// 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.
+//
+
+// Image.h: Defines the egl::Image class representing the EGLimage object.
+
+#ifndef LIBANGLE_IMAGE_H_
+#define LIBANGLE_IMAGE_H_
+
+#include "common/angleutils.h"
+#include "libANGLE/AttributeMap.h"
+#include "libANGLE/Error.h"
+#include "libANGLE/RefCountObject.h"
+
+#include <set>
+
+namespace rx
+{
+class ImageImpl;
+}
+
+namespace egl
+{
+class Image;
+
+class ImageSibling : public RefCountObject
+{
+ public:
+ ImageSibling(GLuint id);
+ virtual ~ImageSibling();
+
+ protected:
+ // Set the image target of this sibling
+ void setTargetImage(egl::Image *imageTarget);
+
+ // Orphan all EGL image sources and targets
+ gl::Error orphanImages();
+
+ private:
+ friend class Image;
+
+ // Called from Image only to add a new source image
+ void addImageSource(egl::Image *imageSource);
+
+ // Called from Image only to remove a source image when the Image is being deleted
+ void removeImageSource(egl::Image *imageSource);
+
+ std::set<Image *> mSourcesOf;
+ BindingPointer<Image> mTargetOf;
+};
+
+class Image final : public RefCountObject
+{
+ public:
+ Image(rx::ImageImpl *impl, EGLenum target, ImageSibling *buffer, const AttributeMap &attribs);
+ ~Image();
+
+ GLenum getInternalFormat() const;
+ size_t getWidth() const;
+ size_t getHeight() const;
+ size_t getSamples() const;
+
+ rx::ImageImpl *getImplementation();
+ const rx::ImageImpl *getImplementation() const;
+
+ private:
+ friend class ImageSibling;
+
+ // Called from ImageSibling only notify the image that a new target sibling exists for state
+ // tracking.
+ void addTargetSibling(ImageSibling *sibling);
+
+ // Called from ImageSibling only to notify the image that a sibling (source or target) has
+ // been respecified and state tracking should be updated.
+ gl::Error orphanSibling(ImageSibling *sibling);
+
+ rx::ImageImpl *mImplementation;
+
+ GLenum mInternalFormat;
+ size_t mWidth;
+ size_t mHeight;
+ size_t mSamples;
+
+ BindingPointer<ImageSibling> mSource;
+ std::set<ImageSibling *> mTargets;
+};
+}
+
+#endif // LIBANGLE_IMAGE_H_
diff --git a/src/3rdparty/angle/src/libANGLE/ImageIndex.cpp b/src/3rdparty/angle/src/libANGLE/ImageIndex.cpp
index ac7302d121..c84e7c5d65 100644
--- a/src/3rdparty/angle/src/libANGLE/ImageIndex.cpp
+++ b/src/3rdparty/angle/src/libANGLE/ImageIndex.cpp
@@ -35,7 +35,8 @@ ImageIndex ImageIndex::Make2D(GLint mipIndex)
ImageIndex ImageIndex::MakeCube(GLenum target, GLint mipIndex)
{
ASSERT(gl::IsCubeMapTextureTarget(target));
- return ImageIndex(target, mipIndex, CubeMapTextureTargetToLayerIndex(target));
+ return ImageIndex(target, mipIndex,
+ static_cast<GLint>(CubeMapTextureTargetToLayerIndex(target)));
}
ImageIndex ImageIndex::Make2DArray(GLint mipIndex, GLint layerIndex)
@@ -50,7 +51,9 @@ ImageIndex ImageIndex::Make3D(GLint mipIndex, GLint layerIndex)
ImageIndex ImageIndex::MakeGeneric(GLenum target, GLint mipIndex)
{
- GLint layerIndex = IsCubeMapTextureTarget(target) ? CubeMapTextureTargetToLayerIndex(target) : ENTIRE_LEVEL;
+ GLint layerIndex = IsCubeMapTextureTarget(target)
+ ? static_cast<GLint>(CubeMapTextureTargetToLayerIndex(target))
+ : ENTIRE_LEVEL;
return ImageIndex(target, mipIndex, layerIndex);
}
@@ -83,30 +86,30 @@ ImageIndex::ImageIndex(GLenum typeIn, GLint mipIndexIn, GLint layerIndexIn)
ImageIndexIterator ImageIndexIterator::Make2D(GLint minMip, GLint maxMip)
{
- return ImageIndexIterator(GL_TEXTURE_2D, rx::Range<GLint>(minMip, maxMip),
- rx::Range<GLint>(ImageIndex::ENTIRE_LEVEL, ImageIndex::ENTIRE_LEVEL), NULL);
+ return ImageIndexIterator(GL_TEXTURE_2D, Range<GLint>(minMip, maxMip),
+ Range<GLint>(ImageIndex::ENTIRE_LEVEL, ImageIndex::ENTIRE_LEVEL), NULL);
}
ImageIndexIterator ImageIndexIterator::MakeCube(GLint minMip, GLint maxMip)
{
- return ImageIndexIterator(GL_TEXTURE_CUBE_MAP, rx::Range<GLint>(minMip, maxMip), rx::Range<GLint>(0, 6), NULL);
+ return ImageIndexIterator(GL_TEXTURE_CUBE_MAP, Range<GLint>(minMip, maxMip), Range<GLint>(0, 6), NULL);
}
ImageIndexIterator ImageIndexIterator::Make3D(GLint minMip, GLint maxMip,
GLint minLayer, GLint maxLayer)
{
- return ImageIndexIterator(GL_TEXTURE_3D, rx::Range<GLint>(minMip, maxMip), rx::Range<GLint>(minLayer, maxLayer), NULL);
+ return ImageIndexIterator(GL_TEXTURE_3D, Range<GLint>(minMip, maxMip), Range<GLint>(minLayer, maxLayer), NULL);
}
ImageIndexIterator ImageIndexIterator::Make2DArray(GLint minMip, GLint maxMip,
const GLsizei *layerCounts)
{
- return ImageIndexIterator(GL_TEXTURE_2D_ARRAY, rx::Range<GLint>(minMip, maxMip),
- rx::Range<GLint>(0, IMPLEMENTATION_MAX_2D_ARRAY_TEXTURE_LAYERS), layerCounts);
+ return ImageIndexIterator(GL_TEXTURE_2D_ARRAY, Range<GLint>(minMip, maxMip),
+ Range<GLint>(0, IMPLEMENTATION_MAX_2D_ARRAY_TEXTURE_LAYERS), layerCounts);
}
-ImageIndexIterator::ImageIndexIterator(GLenum type, const rx::Range<GLint> &mipRange,
- const rx::Range<GLint> &layerRange, const GLsizei *layerCounts)
+ImageIndexIterator::ImageIndexIterator(GLenum type, const Range<GLint> &mipRange,
+ const Range<GLint> &layerRange, const GLsizei *layerCounts)
: mType(type),
mMipRange(mipRange),
mLayerRange(layerRange),
diff --git a/src/3rdparty/angle/src/libANGLE/ImageIndex.h b/src/3rdparty/angle/src/libANGLE/ImageIndex.h
index 820c650f20..b527c7c8ab 100644
--- a/src/3rdparty/angle/src/libANGLE/ImageIndex.h
+++ b/src/3rdparty/angle/src/libANGLE/ImageIndex.h
@@ -61,14 +61,14 @@ class ImageIndexIterator
private:
- ImageIndexIterator(GLenum type, const rx::Range<GLint> &mipRange,
- const rx::Range<GLint> &layerRange, const GLsizei *layerCounts);
+ ImageIndexIterator(GLenum type, const Range<GLint> &mipRange,
+ const Range<GLint> &layerRange, const GLsizei *layerCounts);
GLint maxLayer() const;
GLenum mType;
- rx::Range<GLint> mMipRange;
- rx::Range<GLint> mLayerRange;
+ Range<GLint> mMipRange;
+ Range<GLint> mLayerRange;
const GLsizei *mLayerCounts;
GLint mCurrentMip;
GLint mCurrentLayer;
diff --git a/src/3rdparty/angle/src/libANGLE/IndexRangeCache.cpp b/src/3rdparty/angle/src/libANGLE/IndexRangeCache.cpp
new file mode 100644
index 0000000000..4f165c1b28
--- /dev/null
+++ b/src/3rdparty/angle/src/libANGLE/IndexRangeCache.cpp
@@ -0,0 +1,113 @@
+//
+// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// IndexRangeCache.cpp: Defines the gl::IndexRangeCache class which stores information about
+// ranges of indices.
+
+#include "libANGLE/IndexRangeCache.h"
+
+#include "common/debug.h"
+#include "libANGLE/formatutils.h"
+
+namespace gl
+{
+
+void IndexRangeCache::addRange(GLenum type,
+ size_t offset,
+ size_t count,
+ bool primitiveRestartEnabled,
+ const IndexRange &range)
+{
+ mIndexRangeCache[IndexRangeKey(type, offset, count, primitiveRestartEnabled)] = range;
+}
+
+bool IndexRangeCache::findRange(GLenum type,
+ size_t offset,
+ size_t count,
+ bool primitiveRestartEnabled,
+ IndexRange *outRange) const
+{
+ auto i = mIndexRangeCache.find(IndexRangeKey(type, offset, count, primitiveRestartEnabled));
+ if (i != mIndexRangeCache.end())
+ {
+ if (outRange)
+ {
+ *outRange = i->second;
+ }
+ return true;
+ }
+ else
+ {
+ if (outRange)
+ {
+ *outRange = IndexRange();
+ }
+ return false;
+ }
+}
+
+void IndexRangeCache::invalidateRange(size_t offset, size_t size)
+{
+ size_t invalidateStart = offset;
+ size_t invalidateEnd = offset + size;
+
+ auto i = mIndexRangeCache.begin();
+ while (i != mIndexRangeCache.end())
+ {
+ size_t rangeStart = i->first.offset;
+ size_t rangeEnd = i->first.offset + (GetTypeInfo(i->first.type).bytes * i->first.count);
+
+ if (invalidateEnd < rangeStart || invalidateStart > rangeEnd)
+ {
+ ++i;
+ }
+ else
+ {
+ mIndexRangeCache.erase(i++);
+ }
+ }
+}
+
+void IndexRangeCache::clear()
+{
+ mIndexRangeCache.clear();
+}
+
+IndexRangeCache::IndexRangeKey::IndexRangeKey()
+ : IndexRangeCache::IndexRangeKey(GL_NONE, 0, 0, false)
+{
+}
+
+IndexRangeCache::IndexRangeKey::IndexRangeKey(GLenum type_,
+ size_t offset_,
+ size_t count_,
+ bool primitiveRestartEnabled_)
+ : type(type_), offset(offset_), count(count_), primitiveRestartEnabled(primitiveRestartEnabled_)
+{
+}
+
+bool IndexRangeCache::IndexRangeKey::operator<(const IndexRangeKey &rhs) const
+{
+ if (type != rhs.type)
+ {
+ return type < rhs.type;
+ }
+ if (offset != rhs.offset)
+ {
+ return offset < rhs.offset;
+ }
+ if (count != rhs.count)
+ {
+ return count < rhs.count;
+ }
+ if (primitiveRestartEnabled != rhs.primitiveRestartEnabled)
+ {
+ return primitiveRestartEnabled;
+ }
+ return false;
+}
+
+}
diff --git a/src/3rdparty/angle/src/libANGLE/IndexRangeCache.h b/src/3rdparty/angle/src/libANGLE/IndexRangeCache.h
new file mode 100644
index 0000000000..69de421c13
--- /dev/null
+++ b/src/3rdparty/angle/src/libANGLE/IndexRangeCache.h
@@ -0,0 +1,60 @@
+//
+// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// IndexRangeCache.h: Defines the gl::IndexRangeCache class which stores information about
+// ranges of indices.
+
+#ifndef LIBANGLE_INDEXRANGECACHE_H_
+#define LIBANGLE_INDEXRANGECACHE_H_
+
+#include "common/angleutils.h"
+#include "common/mathutil.h"
+
+#include "angle_gl.h"
+
+#include <map>
+
+namespace gl
+{
+
+class IndexRangeCache
+{
+ public:
+ void addRange(GLenum type,
+ size_t offset,
+ size_t count,
+ bool primitiveRestartEnabled,
+ const IndexRange &range);
+ bool findRange(GLenum type,
+ size_t offset,
+ size_t count,
+ bool primitiveRestartEnabled,
+ IndexRange *outRange) const;
+
+ void invalidateRange(size_t offset, size_t size);
+ void clear();
+
+ private:
+ struct IndexRangeKey
+ {
+ IndexRangeKey();
+ IndexRangeKey(GLenum type, size_t offset, size_t count, bool primitiveRestart);
+
+ bool operator<(const IndexRangeKey &rhs) const;
+
+ GLenum type;
+ size_t offset;
+ size_t count;
+ bool primitiveRestartEnabled;
+ };
+
+ typedef std::map<IndexRangeKey, IndexRange> IndexRangeMap;
+ IndexRangeMap mIndexRangeCache;
+};
+
+}
+
+#endif // LIBANGLE_INDEXRANGECACHE_H_
diff --git a/src/3rdparty/angle/src/libANGLE/Platform.cpp b/src/3rdparty/angle/src/libANGLE/Platform.cpp
index ab75bbba5a..bfcdb1494e 100644
--- a/src/3rdparty/angle/src/libANGLE/Platform.cpp
+++ b/src/3rdparty/angle/src/libANGLE/Platform.cpp
@@ -16,20 +16,20 @@ angle::Platform *currentPlatform = nullptr;
}
// static
-ANGLE_EXPORT angle::Platform *ANGLEPlatformCurrent()
+angle::Platform *ANGLE_APIENTRY ANGLEPlatformCurrent()
{
return currentPlatform;
}
// static
-ANGLE_EXPORT void ANGLEPlatformInitialize(angle::Platform *platformImpl)
+void ANGLE_APIENTRY ANGLEPlatformInitialize(angle::Platform *platformImpl)
{
ASSERT(platformImpl != nullptr);
currentPlatform = platformImpl;
}
// static
-ANGLE_EXPORT void ANGLEPlatformShutdown()
+void ANGLE_APIENTRY ANGLEPlatformShutdown()
{
currentPlatform = nullptr;
}
diff --git a/src/3rdparty/angle/src/libANGLE/Program.cpp b/src/3rdparty/angle/src/libANGLE/Program.cpp
index daf0a403f0..69497c4436 100644
--- a/src/3rdparty/angle/src/libANGLE/Program.cpp
+++ b/src/3rdparty/angle/src/libANGLE/Program.cpp
@@ -11,6 +11,7 @@
#include <algorithm>
+#include "common/BitSetIterator.h"
#include "common/debug.h"
#include "common/platform.h"
#include "common/utilities.h"
@@ -21,72 +22,156 @@
#include "libANGLE/features.h"
#include "libANGLE/renderer/Renderer.h"
#include "libANGLE/renderer/ProgramImpl.h"
+#include "libANGLE/queryconversions.h"
namespace gl
{
-const char * const g_fakepath = "C:\\fakepath";
namespace
{
-unsigned int ParseAndStripArrayIndex(std::string* name)
+void WriteShaderVar(BinaryOutputStream *stream, const sh::ShaderVariable &var)
{
- unsigned int subscript = GL_INVALID_INDEX;
+ stream->writeInt(var.type);
+ stream->writeInt(var.precision);
+ stream->writeString(var.name);
+ stream->writeString(var.mappedName);
+ stream->writeInt(var.arraySize);
+ stream->writeInt(var.staticUse);
+ stream->writeString(var.structName);
+ ASSERT(var.fields.empty());
+}
- // 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->substr(open + 1).c_str());
- name->erase(open);
- }
+void LoadShaderVar(BinaryInputStream *stream, sh::ShaderVariable *var)
+{
+ var->type = stream->readInt<GLenum>();
+ var->precision = stream->readInt<GLenum>();
+ var->name = stream->readString();
+ var->mappedName = stream->readString();
+ var->arraySize = stream->readInt<unsigned int>();
+ var->staticUse = stream->readBool();
+ var->structName = stream->readString();
+}
- return subscript;
+// This simplified cast function doesn't need to worry about advanced concepts like
+// depth range values, or casting to bool.
+template <typename DestT, typename SrcT>
+DestT UniformStateQueryCast(SrcT value);
+
+// From-Float-To-Integer Casts
+template <>
+GLint UniformStateQueryCast(GLfloat value)
+{
+ return clampCast<GLint>(roundf(value));
}
+template <>
+GLuint UniformStateQueryCast(GLfloat value)
+{
+ return clampCast<GLuint>(roundf(value));
}
-AttributeBindings::AttributeBindings()
+// From-Integer-to-Integer Casts
+template <>
+GLint UniformStateQueryCast(GLuint value)
{
+ return clampCast<GLint>(value);
}
-AttributeBindings::~AttributeBindings()
+template <>
+GLuint UniformStateQueryCast(GLint value)
{
+ return clampCast<GLuint>(value);
}
-InfoLog::InfoLog() : mInfoLog(NULL)
+// From-Boolean-to-Anything Casts
+template <>
+GLfloat UniformStateQueryCast(GLboolean value)
{
+ return (value == GL_TRUE ? 1.0f : 0.0f);
}
-InfoLog::~InfoLog()
+template <>
+GLint UniformStateQueryCast(GLboolean value)
{
- delete[] mInfoLog;
+ return (value == GL_TRUE ? 1 : 0);
}
+template <>
+GLuint UniformStateQueryCast(GLboolean value)
+{
+ return (value == GL_TRUE ? 1u : 0u);
+}
-int InfoLog::getLength() const
+// Default to static_cast
+template <typename DestT, typename SrcT>
+DestT UniformStateQueryCast(SrcT value)
{
- if (!mInfoLog)
+ return static_cast<DestT>(value);
+}
+
+template <typename SrcT, typename DestT>
+void UniformStateQueryCastLoop(DestT *dataOut, const uint8_t *srcPointer, int components)
+{
+ for (int comp = 0; comp < components; ++comp)
{
- return 0;
+ // We only work with strides of 4 bytes for uniform components. (GLfloat/GLint)
+ // Don't use SrcT stride directly since GLboolean has a stride of 1 byte.
+ size_t offset = comp * 4;
+ const SrcT *typedSrcPointer = reinterpret_cast<const SrcT *>(&srcPointer[offset]);
+ dataOut[comp] = UniformStateQueryCast<DestT>(*typedSrcPointer);
}
- else
+}
+
+bool UniformInList(const std::vector<LinkedUniform> &list, const std::string &name)
+{
+ for (const LinkedUniform &uniform : list)
{
- return strlen(mInfoLog) + 1;
+ if (uniform.name == name)
+ return true;
}
+
+ return false;
+}
+
+} // anonymous namespace
+
+const char *const g_fakepath = "C:\\fakepath";
+
+AttributeBindings::AttributeBindings()
+{
+}
+
+AttributeBindings::~AttributeBindings()
+{
+}
+
+InfoLog::InfoLog()
+{
+}
+
+InfoLog::~InfoLog()
+{
}
-void InfoLog::getLog(GLsizei bufSize, GLsizei *length, char *infoLog)
+size_t InfoLog::getLength() const
{
- int index = 0;
+ const std::string &logString = mStream.str();
+ return logString.empty() ? 0 : logString.length() + 1;
+}
+
+void InfoLog::getLog(GLsizei bufSize, GLsizei *length, char *infoLog) const
+{
+ size_t index = 0;
if (bufSize > 0)
{
- if (mInfoLog)
+ const std::string str(mStream.str());
+
+ if (!str.empty())
{
- index = std::min(bufSize - 1, (int)strlen(mInfoLog));
- memcpy(infoLog, mInfoLog, index);
+ index = std::min(static_cast<size_t>(bufSize) - 1, str.length());
+ memcpy(infoLog, str.c_str(), index);
}
infoLog[index] = '\0';
@@ -94,7 +179,7 @@ void InfoLog::getLog(GLsizei bufSize, GLsizei *length, char *infoLog)
if (length)
{
- *length = index;
+ *length = static_cast<GLsizei>(index);
}
}
@@ -116,89 +201,125 @@ void InfoLog::appendSanitized(const char *message)
}
while (found != std::string::npos);
- append("%s", msg.c_str());
+ mStream << message << std::endl;
}
-void InfoLog::append(const char *format, ...)
+void InfoLog::reset()
{
- if (!format)
- {
- return;
- }
+}
- va_list vararg;
- va_start(vararg, format);
- size_t infoLength = vsnprintf(NULL, 0, format, vararg);
- va_end(vararg);
+VariableLocation::VariableLocation()
+ : name(),
+ element(0),
+ index(0)
+{
+}
- char *logPointer = NULL;
+VariableLocation::VariableLocation(const std::string &name, unsigned int element, unsigned int index)
+ : name(name),
+ element(element),
+ index(index)
+{
+}
+
+Program::Data::Data()
+ : mLabel(),
+ mAttachedFragmentShader(nullptr),
+ mAttachedVertexShader(nullptr),
+ mTransformFeedbackBufferMode(GL_INTERLEAVED_ATTRIBS),
+ mBinaryRetrieveableHint(false)
+{
+}
- if (!mInfoLog)
+Program::Data::~Data()
+{
+ if (mAttachedVertexShader != nullptr)
{
- mInfoLog = new char[infoLength + 2];
- logPointer = mInfoLog;
+ mAttachedVertexShader->release();
}
- else
- {
- size_t currentlogLength = strlen(mInfoLog);
- char *newLog = new char[currentlogLength + infoLength + 2];
- strcpy(newLog, mInfoLog);
- delete[] mInfoLog;
- mInfoLog = newLog;
-
- logPointer = mInfoLog + currentlogLength;
+ if (mAttachedFragmentShader != nullptr)
+ {
+ mAttachedFragmentShader->release();
}
+}
- va_start(vararg, format);
- vsnprintf(logPointer, infoLength, format, vararg);
- va_end(vararg);
-
- logPointer[infoLength] = 0;
- strcpy(logPointer + infoLength, "\n");
+const std::string &Program::Data::getLabel()
+{
+ return mLabel;
}
-void InfoLog::reset()
+const LinkedUniform *Program::Data::getUniformByName(const std::string &name) const
{
- if (mInfoLog)
+ for (const LinkedUniform &linkedUniform : mUniforms)
{
- delete [] mInfoLog;
- mInfoLog = NULL;
+ if (linkedUniform.name == name)
+ {
+ return &linkedUniform;
+ }
}
-}
-VariableLocation::VariableLocation()
- : name(), element(0), index(0)
-{
+ return nullptr;
}
-VariableLocation::VariableLocation(const std::string &name, unsigned int element, unsigned int index)
- : name(name), element(element), index(index)
+GLint Program::Data::getUniformLocation(const std::string &name) const
{
-}
+ size_t subscript = GL_INVALID_INDEX;
+ std::string baseName = gl::ParseUniformName(name, &subscript);
-LinkedVarying::LinkedVarying()
-{
+ for (size_t location = 0; location < mUniformLocations.size(); ++location)
+ {
+ const VariableLocation &uniformLocation = mUniformLocations[location];
+ const LinkedUniform &uniform = mUniforms[uniformLocation.index];
+
+ if (uniform.name == baseName)
+ {
+ if ((uniform.isArray() && uniformLocation.element == subscript) ||
+ (subscript == GL_INVALID_INDEX))
+ {
+ return static_cast<GLint>(location);
+ }
+ }
+ }
+
+ return -1;
}
-LinkedVarying::LinkedVarying(const std::string &name, GLenum type, GLsizei size, const std::string &semanticName,
- unsigned int semanticIndex, unsigned int semanticIndexCount)
- : name(name), type(type), size(size), semanticName(semanticName), semanticIndex(semanticIndex), semanticIndexCount(semanticIndexCount)
+GLuint Program::Data::getUniformIndex(const std::string &name) const
{
+ size_t subscript = GL_INVALID_INDEX;
+ std::string baseName = gl::ParseUniformName(name, &subscript);
+
+ // The app is not allowed to specify array indices other than 0 for arrays of basic types
+ if (subscript != 0 && subscript != GL_INVALID_INDEX)
+ {
+ return GL_INVALID_INDEX;
+ }
+
+ for (size_t index = 0; index < mUniforms.size(); index++)
+ {
+ const LinkedUniform &uniform = mUniforms[index];
+ if (uniform.name == baseName)
+ {
+ if (uniform.isArray() || subscript == GL_INVALID_INDEX)
+ {
+ return static_cast<GLuint>(index);
+ }
+ }
+ }
+
+ return GL_INVALID_INDEX;
}
-Program::Program(rx::ProgramImpl *impl, ResourceManager *manager, GLuint handle)
- : mProgram(impl),
+Program::Program(rx::ImplFactory *factory, ResourceManager *manager, GLuint handle)
+ : mProgram(factory->createProgram(mData)),
mValidated(false),
- mTransformFeedbackVaryings(),
- mTransformFeedbackBufferMode(GL_NONE),
- mFragmentShader(NULL),
- mVertexShader(NULL),
mLinked(false),
mDeleteStatus(false),
mRefCount(0),
mResourceManager(manager),
- mHandle(handle)
+ mHandle(handle),
+ mSamplerUniformRange(0, 0)
{
ASSERT(mProgram);
@@ -210,40 +331,40 @@ Program::~Program()
{
unlink(true);
- if (mVertexShader != NULL)
- {
- mVertexShader->release();
- }
+ SafeDelete(mProgram);
+}
- if (mFragmentShader != NULL)
- {
- mFragmentShader->release();
- }
+void Program::setLabel(const std::string &label)
+{
+ mData.mLabel = label;
+}
- SafeDelete(mProgram);
+const std::string &Program::getLabel() const
+{
+ return mData.mLabel;
}
bool Program::attachShader(Shader *shader)
{
if (shader->getType() == GL_VERTEX_SHADER)
{
- if (mVertexShader)
+ if (mData.mAttachedVertexShader)
{
return false;
}
- mVertexShader = shader;
- mVertexShader->addRef();
+ mData.mAttachedVertexShader = shader;
+ mData.mAttachedVertexShader->addRef();
}
else if (shader->getType() == GL_FRAGMENT_SHADER)
{
- if (mFragmentShader)
+ if (mData.mAttachedFragmentShader)
{
return false;
}
- mFragmentShader = shader;
- mFragmentShader->addRef();
+ mData.mAttachedFragmentShader = shader;
+ mData.mAttachedFragmentShader->addRef();
}
else UNREACHABLE();
@@ -254,23 +375,23 @@ bool Program::detachShader(Shader *shader)
{
if (shader->getType() == GL_VERTEX_SHADER)
{
- if (mVertexShader != shader)
+ if (mData.mAttachedVertexShader != shader)
{
return false;
}
- mVertexShader->release();
- mVertexShader = NULL;
+ shader->release();
+ mData.mAttachedVertexShader = nullptr;
}
else if (shader->getType() == GL_FRAGMENT_SHADER)
{
- if (mFragmentShader != shader)
+ if (mData.mAttachedFragmentShader != shader)
{
return false;
}
- mFragmentShader->release();
- mFragmentShader = NULL;
+ shader->release();
+ mData.mAttachedFragmentShader = nullptr;
}
else UNREACHABLE();
@@ -279,7 +400,7 @@ bool Program::detachShader(Shader *shader)
int Program::getAttachedShadersCount() const
{
- return (mVertexShader ? 1 : 0) + (mFragmentShader ? 1 : 0);
+ return (mData.mAttachedVertexShader ? 1 : 0) + (mData.mAttachedFragmentShader ? 1 : 0);
}
void AttributeBindings::bindAttributeLocation(GLuint index, const char *name)
@@ -303,65 +424,63 @@ void Program::bindAttributeLocation(GLuint index, const char *name)
// Links the HLSL code of the vertex and pixel shader by matching up their varyings,
// compiling them into binaries, determining the attribute mappings, and collecting
// a list of uniforms
-Error Program::link(const Data &data)
+Error Program::link(const gl::Data &data)
{
unlink(false);
mInfoLog.reset();
resetUniformBlockBindings();
- if (!mFragmentShader || !mFragmentShader->isCompiled())
+ if (!mData.mAttachedFragmentShader || !mData.mAttachedFragmentShader->isCompiled())
{
return Error(GL_NO_ERROR);
}
- ASSERT(mFragmentShader->getType() == GL_FRAGMENT_SHADER);
+ ASSERT(mData.mAttachedFragmentShader->getType() == GL_FRAGMENT_SHADER);
- if (!mVertexShader || !mVertexShader->isCompiled())
+ if (!mData.mAttachedVertexShader || !mData.mAttachedVertexShader->isCompiled())
{
return Error(GL_NO_ERROR);
}
- ASSERT(mVertexShader->getType() == GL_VERTEX_SHADER);
+ ASSERT(mData.mAttachedVertexShader->getType() == GL_VERTEX_SHADER);
- if (!linkAttributes(mInfoLog, mAttributeBindings, mVertexShader))
+ if (!linkAttributes(data, mInfoLog, mAttributeBindings, mData.mAttachedVertexShader))
{
return Error(GL_NO_ERROR);
}
- int registers;
- std::vector<LinkedVarying> linkedVaryings;
- rx::LinkResult result = mProgram->link(data, mInfoLog, mFragmentShader, mVertexShader, mTransformFeedbackVaryings, mTransformFeedbackBufferMode,
- &registers, &linkedVaryings, &mOutputVariables);
- if (result.error.isError() || !result.linkSuccess)
+ if (!linkVaryings(mInfoLog, mData.mAttachedVertexShader, mData.mAttachedFragmentShader))
{
- return result.error;
+ return Error(GL_NO_ERROR);
}
- if (!mProgram->linkUniforms(mInfoLog, *mVertexShader, *mFragmentShader, *data.caps))
+ if (!linkUniforms(mInfoLog, *data.caps))
{
return Error(GL_NO_ERROR);
}
- if (!linkUniformBlocks(mInfoLog, *mVertexShader, *mFragmentShader, *data.caps))
+ if (!linkUniformBlocks(mInfoLog, *data.caps))
{
return Error(GL_NO_ERROR);
}
- if (!gatherTransformFeedbackLinkedVaryings(mInfoLog, linkedVaryings, mTransformFeedbackVaryings,
- mTransformFeedbackBufferMode, &mProgram->getTransformFeedbackLinkedVaryings(), *data.caps))
+ const auto &mergedVaryings = getMergedVaryings();
+
+ if (!linkValidateTransformFeedback(mInfoLog, mergedVaryings, *data.caps))
{
return Error(GL_NO_ERROR);
}
- // TODO: The concept of "executables" is D3D only, and as such this belongs in ProgramD3D. It must be called,
- // however, last in this function, so it can't simply be moved to ProgramD3D::link without further shuffling.
- result = mProgram->compileProgramExecutables(mInfoLog, mFragmentShader, mVertexShader, registers);
+ linkOutputVariables();
+
+ rx::LinkResult result = mProgram->link(data, mInfoLog);
if (result.error.isError() || !result.linkSuccess)
{
- mInfoLog.append("Failed to create D3D shaders.");
- unlink(false);
return result.error;
}
+ gatherTransformFeedbackVaryings(mergedVaryings);
+ gatherInterfaceBlockInfo();
+
mLinked = true;
return gl::Error(GL_NO_ERROR);
}
@@ -384,30 +503,33 @@ void Program::unlink(bool destroy)
{
if (destroy) // Object being destructed
{
- if (mFragmentShader)
+ if (mData.mAttachedFragmentShader)
{
- mFragmentShader->release();
- mFragmentShader = NULL;
+ mData.mAttachedFragmentShader->release();
+ mData.mAttachedFragmentShader = nullptr;
}
- if (mVertexShader)
+ if (mData.mAttachedVertexShader)
{
- mVertexShader->release();
- mVertexShader = NULL;
+ mData.mAttachedVertexShader->release();
+ mData.mAttachedVertexShader = nullptr;
}
}
- std::fill(mLinkedAttribute, mLinkedAttribute + ArraySize(mLinkedAttribute), sh::Attribute());
- mOutputVariables.clear();
-
- mProgram->reset();
+ mData.mAttributes.clear();
+ mData.mActiveAttribLocationsMask.reset();
+ mData.mTransformFeedbackVaryingVars.clear();
+ mData.mUniforms.clear();
+ mData.mUniformLocations.clear();
+ mData.mUniformBlocks.clear();
+ mData.mOutputVariables.clear();
mValidated = false;
mLinked = false;
}
-bool Program::isLinked()
+bool Program::isLinked() const
{
return mLinked;
}
@@ -419,22 +541,20 @@ Error Program::loadBinary(GLenum binaryFormat, const void *binary, GLsizei lengt
#if ANGLE_PROGRAM_BINARY_LOAD != ANGLE_ENABLED
return Error(GL_NO_ERROR);
#else
- ASSERT(binaryFormat == mProgram->getBinaryFormat());
-
- BinaryInputStream stream(binary, length);
-
- GLenum format = stream.readInt<GLenum>();
- if (format != mProgram->getBinaryFormat())
+ ASSERT(binaryFormat == GL_PROGRAM_BINARY_ANGLE);
+ if (binaryFormat != GL_PROGRAM_BINARY_ANGLE)
{
- mInfoLog.append("Invalid program binary format.");
+ mInfoLog << "Invalid program binary format.";
return Error(GL_NO_ERROR);
}
+ BinaryInputStream stream(binary, length);
+
int majorVersion = stream.readInt<int>();
int minorVersion = stream.readInt<int>();
if (majorVersion != ANGLE_MAJOR_VERSION || minorVersion != ANGLE_MINOR_VERSION)
{
- mInfoLog.append("Invalid program binary version.");
+ mInfoLog << "Invalid program binary version.";
return Error(GL_NO_ERROR);
}
@@ -442,19 +562,105 @@ Error Program::loadBinary(GLenum binaryFormat, const void *binary, GLsizei lengt
stream.readBytes(commitString, ANGLE_COMMIT_HASH_SIZE);
if (memcmp(commitString, ANGLE_COMMIT_HASH, sizeof(unsigned char) * ANGLE_COMMIT_HASH_SIZE) != 0)
{
- mInfoLog.append("Invalid program binary version.");
+ mInfoLog << "Invalid program binary version.";
return Error(GL_NO_ERROR);
}
- for (int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
+ static_assert(MAX_VERTEX_ATTRIBS <= sizeof(unsigned long) * 8,
+ "Too many vertex attribs for mask");
+ mData.mActiveAttribLocationsMask = stream.readInt<unsigned long>();
+
+ unsigned int attribCount = stream.readInt<unsigned int>();
+ ASSERT(mData.mAttributes.empty());
+ for (unsigned int attribIndex = 0; attribIndex < attribCount; ++attribIndex)
+ {
+ sh::Attribute attrib;
+ LoadShaderVar(&stream, &attrib);
+ attrib.location = stream.readInt<int>();
+ mData.mAttributes.push_back(attrib);
+ }
+
+ unsigned int uniformCount = stream.readInt<unsigned int>();
+ ASSERT(mData.mUniforms.empty());
+ for (unsigned int uniformIndex = 0; uniformIndex < uniformCount; ++uniformIndex)
{
- stream.readInt(&mLinkedAttribute[i].type);
- stream.readString(&mLinkedAttribute[i].name);
- stream.readInt(&mProgram->getShaderAttributes()[i].type);
- stream.readString(&mProgram->getShaderAttributes()[i].name);
- stream.readInt(&mProgram->getSemanticIndexes()[i]);
+ LinkedUniform uniform;
+ LoadShaderVar(&stream, &uniform);
+
+ uniform.blockIndex = stream.readInt<int>();
+ uniform.blockInfo.offset = stream.readInt<int>();
+ uniform.blockInfo.arrayStride = stream.readInt<int>();
+ uniform.blockInfo.matrixStride = stream.readInt<int>();
+ uniform.blockInfo.isRowMajorMatrix = stream.readBool();
+
+ mData.mUniforms.push_back(uniform);
+ }
+
+ const unsigned int uniformIndexCount = stream.readInt<unsigned int>();
+ ASSERT(mData.mUniformLocations.empty());
+ for (unsigned int uniformIndexIndex = 0; uniformIndexIndex < uniformIndexCount;
+ uniformIndexIndex++)
+ {
+ VariableLocation variable;
+ stream.readString(&variable.name);
+ stream.readInt(&variable.element);
+ stream.readInt(&variable.index);
+
+ mData.mUniformLocations.push_back(variable);
+ }
+
+ unsigned int uniformBlockCount = stream.readInt<unsigned int>();
+ ASSERT(mData.mUniformBlocks.empty());
+ for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < uniformBlockCount;
+ ++uniformBlockIndex)
+ {
+ UniformBlock uniformBlock;
+ stream.readString(&uniformBlock.name);
+ stream.readBool(&uniformBlock.isArray);
+ stream.readInt(&uniformBlock.arrayElement);
+ stream.readInt(&uniformBlock.dataSize);
+ stream.readBool(&uniformBlock.vertexStaticUse);
+ stream.readBool(&uniformBlock.fragmentStaticUse);
+
+ unsigned int numMembers = stream.readInt<unsigned int>();
+ for (unsigned int blockMemberIndex = 0; blockMemberIndex < numMembers; blockMemberIndex++)
+ {
+ uniformBlock.memberUniformIndexes.push_back(stream.readInt<unsigned int>());
+ }
+
+ mData.mUniformBlocks.push_back(uniformBlock);
}
+ unsigned int transformFeedbackVaryingCount = stream.readInt<unsigned int>();
+ ASSERT(mData.mTransformFeedbackVaryingVars.empty());
+ for (unsigned int transformFeedbackVaryingIndex = 0;
+ transformFeedbackVaryingIndex < transformFeedbackVaryingCount;
+ ++transformFeedbackVaryingIndex)
+ {
+ sh::Varying varying;
+ stream.readInt(&varying.arraySize);
+ stream.readInt(&varying.type);
+ stream.readString(&varying.name);
+
+ mData.mTransformFeedbackVaryingVars.push_back(varying);
+ }
+
+ stream.readInt(&mData.mTransformFeedbackBufferMode);
+
+ unsigned int outputVarCount = stream.readInt<unsigned int>();
+ for (unsigned int outputIndex = 0; outputIndex < outputVarCount; ++outputIndex)
+ {
+ int locationIndex = stream.readInt<int>();
+ VariableLocation locationData;
+ stream.readInt(&locationData.element);
+ stream.readInt(&locationData.index);
+ stream.readString(&locationData.name);
+ mData.mOutputVariables[locationIndex] = locationData;
+ }
+
+ stream.readInt(&mSamplerUniformRange.start);
+ stream.readInt(&mSamplerUniformRange.end);
+
rx::LinkResult result = mProgram->load(mInfoLog, &stream);
if (result.error.isError() || !result.linkSuccess)
{
@@ -470,32 +676,93 @@ Error Program::saveBinary(GLenum *binaryFormat, void *binary, GLsizei bufSize, G
{
if (binaryFormat)
{
- *binaryFormat = mProgram->getBinaryFormat();
+ *binaryFormat = GL_PROGRAM_BINARY_ANGLE;
}
BinaryOutputStream stream;
- stream.writeInt(mProgram->getBinaryFormat());
stream.writeInt(ANGLE_MAJOR_VERSION);
stream.writeInt(ANGLE_MINOR_VERSION);
stream.writeBytes(reinterpret_cast<const unsigned char*>(ANGLE_COMMIT_HASH), ANGLE_COMMIT_HASH_SIZE);
- for (unsigned int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
+ stream.writeInt(mData.mActiveAttribLocationsMask.to_ulong());
+
+ stream.writeInt(mData.mAttributes.size());
+ for (const sh::Attribute &attrib : mData.mAttributes)
+ {
+ WriteShaderVar(&stream, attrib);
+ stream.writeInt(attrib.location);
+ }
+
+ stream.writeInt(mData.mUniforms.size());
+ for (const gl::LinkedUniform &uniform : mData.mUniforms)
+ {
+ WriteShaderVar(&stream, uniform);
+
+ // FIXME: referenced
+
+ stream.writeInt(uniform.blockIndex);
+ stream.writeInt(uniform.blockInfo.offset);
+ stream.writeInt(uniform.blockInfo.arrayStride);
+ stream.writeInt(uniform.blockInfo.matrixStride);
+ stream.writeInt(uniform.blockInfo.isRowMajorMatrix);
+ }
+
+ stream.writeInt(mData.mUniformLocations.size());
+ for (const auto &variable : mData.mUniformLocations)
{
- stream.writeInt(mLinkedAttribute[i].type);
- stream.writeString(mLinkedAttribute[i].name);
- stream.writeInt(mProgram->getShaderAttributes()[i].type);
- stream.writeString(mProgram->getShaderAttributes()[i].name);
- stream.writeInt(mProgram->getSemanticIndexes()[i]);
+ stream.writeString(variable.name);
+ stream.writeInt(variable.element);
+ stream.writeInt(variable.index);
}
+ stream.writeInt(mData.mUniformBlocks.size());
+ for (const UniformBlock &uniformBlock : mData.mUniformBlocks)
+ {
+ stream.writeString(uniformBlock.name);
+ stream.writeInt(uniformBlock.isArray);
+ stream.writeInt(uniformBlock.arrayElement);
+ stream.writeInt(uniformBlock.dataSize);
+
+ stream.writeInt(uniformBlock.vertexStaticUse);
+ stream.writeInt(uniformBlock.fragmentStaticUse);
+
+ stream.writeInt(uniformBlock.memberUniformIndexes.size());
+ for (unsigned int memberUniformIndex : uniformBlock.memberUniformIndexes)
+ {
+ stream.writeInt(memberUniformIndex);
+ }
+ }
+
+ stream.writeInt(mData.mTransformFeedbackVaryingVars.size());
+ for (const sh::Varying &varying : mData.mTransformFeedbackVaryingVars)
+ {
+ stream.writeInt(varying.arraySize);
+ stream.writeInt(varying.type);
+ stream.writeString(varying.name);
+ }
+
+ stream.writeInt(mData.mTransformFeedbackBufferMode);
+
+ stream.writeInt(mData.mOutputVariables.size());
+ for (const auto &outputPair : mData.mOutputVariables)
+ {
+ stream.writeInt(outputPair.first);
+ stream.writeInt(outputPair.second.element);
+ stream.writeInt(outputPair.second.index);
+ stream.writeString(outputPair.second.name);
+ }
+
+ stream.writeInt(mSamplerUniformRange.start);
+ stream.writeInt(mSamplerUniformRange.end);
+
gl::Error error = mProgram->save(&stream);
if (error.isError())
{
return error;
}
- GLsizei streamLength = stream.length();
+ GLsizei streamLength = static_cast<GLsizei>(stream.length());
const void *streamData = stream.data();
if (streamLength > bufSize)
@@ -532,7 +799,7 @@ Error Program::saveBinary(GLenum *binaryFormat, void *binary, GLsizei bufSize, G
GLint Program::getBinaryLength() const
{
GLint length;
- Error error = saveBinary(NULL, NULL, std::numeric_limits<GLint>::max(), &length);
+ Error error = saveBinary(nullptr, nullptr, std::numeric_limits<GLint>::max(), &length);
if (error.isError())
{
return 0;
@@ -541,6 +808,18 @@ GLint Program::getBinaryLength() const
return length;
}
+void Program::setBinaryRetrievableHint(bool retrievable)
+{
+ // TODO(jmadill) : replace with dirty bits
+ mProgram->setBinaryRetrievableHint(retrievable);
+ mData.mBinaryRetrieveableHint = retrievable;
+}
+
+bool Program::getBinaryRetrievableHint() const
+{
+ return mData.mBinaryRetrieveableHint;
+}
+
void Program::release()
{
mRefCount--;
@@ -563,33 +842,33 @@ unsigned int Program::getRefCount() const
int Program::getInfoLogLength() const
{
- return mInfoLog.getLength();
+ return static_cast<int>(mInfoLog.getLength());
}
-void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog)
+void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog) const
{
return mInfoLog.getLog(bufSize, length, infoLog);
}
-void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders)
+void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders) const
{
int total = 0;
- if (mVertexShader)
+ if (mData.mAttachedVertexShader)
{
if (total < maxCount)
{
- shaders[total] = mVertexShader->getHandle();
+ shaders[total] = mData.mAttachedVertexShader->getHandle();
}
total++;
}
- if (mFragmentShader)
+ if (mData.mAttachedFragmentShader)
{
if (total < maxCount)
{
- shaders[total] = mFragmentShader->getHandle();
+ shaders[total] = mData.mAttachedFragmentShader->getHandle();
}
total++;
@@ -601,66 +880,28 @@ void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shade
}
}
-GLuint Program::getAttributeLocation(const std::string &name)
+GLuint Program::getAttributeLocation(const std::string &name) const
{
- for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
+ for (const sh::Attribute &attribute : mData.mAttributes)
{
- if (mLinkedAttribute[index].name == name)
+ if (attribute.name == name && attribute.staticUse)
{
- return index;
+ return attribute.location;
}
}
return static_cast<GLuint>(-1);
}
-int Program::getSemanticIndex(int attributeIndex)
+bool Program::isAttribLocationActive(size_t attribLocation) const
{
- ASSERT(attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS);
-
- return mProgram->getSemanticIndexes()[attributeIndex];
+ ASSERT(attribLocation < mData.mActiveAttribLocationsMask.size());
+ return mData.mActiveAttribLocationsMask[attribLocation];
}
void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
{
- if (mLinked)
- {
- // Skip over inactive attributes
- unsigned int activeAttribute = 0;
- unsigned int attribute;
- for (attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++)
- {
- if (mLinkedAttribute[attribute].name.empty())
- {
- continue;
- }
-
- if (activeAttribute == index)
- {
- break;
- }
-
- activeAttribute++;
- }
-
- if (bufsize > 0)
- {
- const char *string = mLinkedAttribute[attribute].name.c_str();
-
- strncpy(name, string, bufsize);
- name[bufsize - 1] = '\0';
-
- if (length)
- {
- *length = strlen(name);
- }
- }
-
- *size = 1; // Always a single 'type' instance
-
- *type = mLinkedAttribute[attribute].type;
- }
- else
+ if (!mLinked)
{
if (bufsize > 0)
{
@@ -674,92 +915,114 @@ void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length,
*type = GL_NONE;
*size = 1;
+ return;
}
-}
-GLint Program::getActiveAttributeCount()
-{
- int count = 0;
+ size_t attributeIndex = 0;
- if (mLinked)
+ for (const sh::Attribute &attribute : mData.mAttributes)
{
- for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
+ // Skip over inactive attributes
+ if (attribute.staticUse)
{
- if (!mLinkedAttribute[attributeIndex].name.empty())
+ if (static_cast<size_t>(index) == attributeIndex)
{
- count++;
+ break;
}
+ attributeIndex++;
}
}
- return count;
-}
-
-GLint Program::getActiveAttributeMaxLength()
-{
- int maxLength = 0;
+ ASSERT(index == attributeIndex && attributeIndex < mData.mAttributes.size());
+ const sh::Attribute &attrib = mData.mAttributes[attributeIndex];
- if (mLinked)
+ if (bufsize > 0)
{
- for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
+ const char *string = attrib.name.c_str();
+
+ strncpy(name, string, bufsize);
+ name[bufsize - 1] = '\0';
+
+ if (length)
{
- if (!mLinkedAttribute[attributeIndex].name.empty())
- {
- maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength);
- }
+ *length = static_cast<GLsizei>(strlen(name));
}
}
- return maxLength;
+ // Always a single 'type' instance
+ *size = 1;
+ *type = attrib.type;
}
-// Returns one more than the highest sampler index used.
-GLint Program::getUsedSamplerRange(SamplerType type)
+GLint Program::getActiveAttributeCount() const
{
- return mProgram->getUsedSamplerRange(type);
-}
+ if (!mLinked)
+ {
+ return 0;
+ }
-bool Program::usesPointSize() const
-{
- return mProgram->usesPointSize();
-}
+ GLint count = 0;
-GLint Program::getSamplerMapping(SamplerType type, unsigned int samplerIndex, const Caps &caps)
-{
- return mProgram->getSamplerMapping(type, samplerIndex, caps);
+ for (const sh::Attribute &attrib : mData.mAttributes)
+ {
+ count += (attrib.staticUse ? 1 : 0);
+ }
+
+ return count;
}
-GLenum Program::getSamplerTextureType(SamplerType type, unsigned int samplerIndex)
+GLint Program::getActiveAttributeMaxLength() const
{
- return mProgram->getSamplerTextureType(type, samplerIndex);
+ if (!mLinked)
+ {
+ return 0;
+ }
+
+ size_t maxLength = 0;
+
+ for (const sh::Attribute &attrib : mData.mAttributes)
+ {
+ if (attrib.staticUse)
+ {
+ maxLength = std::max(attrib.name.length() + 1, maxLength);
+ }
+ }
+
+ return static_cast<GLint>(maxLength);
}
GLint Program::getFragDataLocation(const std::string &name) const
{
std::string baseName(name);
unsigned int arrayIndex = ParseAndStripArrayIndex(&baseName);
- for (auto locationIt = mOutputVariables.begin(); locationIt != mOutputVariables.end(); locationIt++)
+ for (auto outputPair : mData.mOutputVariables)
{
- const VariableLocation &outputVariable = locationIt->second;
+ const VariableLocation &outputVariable = outputPair.second;
if (outputVariable.name == baseName && (arrayIndex == GL_INVALID_INDEX || arrayIndex == outputVariable.element))
{
- return static_cast<GLint>(locationIt->first);
+ return static_cast<GLint>(outputPair.first);
}
}
return -1;
}
-void Program::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
+void Program::getActiveUniform(GLuint index,
+ GLsizei bufsize,
+ GLsizei *length,
+ GLint *size,
+ GLenum *type,
+ GLchar *name) const
{
if (mLinked)
{
- ASSERT(index < mProgram->getUniforms().size()); // index must be smaller than getActiveUniformCount()
- LinkedUniform *uniform = mProgram->getUniforms()[index];
+ // index must be smaller than getActiveUniformCount()
+ ASSERT(index < mData.mUniforms.size());
+ const LinkedUniform &uniform = mData.mUniforms[index];
if (bufsize > 0)
{
- std::string string = uniform->name;
- if (uniform->isArray())
+ std::string string = uniform.name;
+ if (uniform.isArray())
{
string += "[0]";
}
@@ -769,12 +1032,12 @@ void Program::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, G
if (length)
{
- *length = strlen(name);
+ *length = static_cast<GLsizei>(strlen(name));
}
}
- *size = uniform->elementCount();
- *type = uniform->type;
+ *size = uniform.elementCount();
+ *type = uniform.type;
}
else
{
@@ -793,11 +1056,11 @@ void Program::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, G
}
}
-GLint Program::getActiveUniformCount()
+GLint Program::getActiveUniformCount() const
{
if (mLinked)
{
- return mProgram->getUniforms().size();
+ return static_cast<GLint>(mData.mUniforms.size());
}
else
{
@@ -805,19 +1068,18 @@ GLint Program::getActiveUniformCount()
}
}
-GLint Program::getActiveUniformMaxLength()
+GLint Program::getActiveUniformMaxLength() const
{
- int maxLength = 0;
+ size_t maxLength = 0;
if (mLinked)
{
- unsigned int numUniforms = mProgram->getUniforms().size();
- for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
+ for (const LinkedUniform &uniform : mData.mUniforms)
{
- if (!mProgram->getUniforms()[uniformIndex]->name.empty())
+ if (!uniform.name.empty())
{
- int length = (int)(mProgram->getUniforms()[uniformIndex]->name.length() + 1);
- if (mProgram->getUniforms()[uniformIndex]->isArray())
+ size_t length = uniform.name.length() + 1u;
+ if (uniform.isArray())
{
length += 3; // Counting in "[0]".
}
@@ -826,12 +1088,13 @@ GLint Program::getActiveUniformMaxLength()
}
}
- return maxLength;
+ return static_cast<GLint>(maxLength);
}
GLint Program::getActiveUniformi(GLuint index, GLenum pname) const
{
- const gl::LinkedUniform& uniform = *mProgram->getUniforms()[index];
+ ASSERT(static_cast<size_t>(index) < mData.mUniforms.size());
+ const gl::LinkedUniform &uniform = mData.mUniforms[index];
switch (pname)
{
case GL_UNIFORM_TYPE: return static_cast<GLint>(uniform.type);
@@ -851,159 +1114,165 @@ GLint Program::getActiveUniformi(GLuint index, GLenum pname) const
bool Program::isValidUniformLocation(GLint location) const
{
- ASSERT(rx::IsIntegerCastSafe<GLint>(mProgram->getUniformIndices().size()));
- return (location >= 0 && location < static_cast<GLint>(mProgram->getUniformIndices().size()));
+ ASSERT(rx::IsIntegerCastSafe<GLint>(mData.mUniformLocations.size()));
+ return (location >= 0 && static_cast<size_t>(location) < mData.mUniformLocations.size());
}
-LinkedUniform *Program::getUniformByLocation(GLint location) const
+const LinkedUniform &Program::getUniformByLocation(GLint location) const
{
- return mProgram->getUniformByLocation(location);
+ ASSERT(location >= 0 && static_cast<size_t>(location) < mData.mUniformLocations.size());
+ return mData.mUniforms[mData.mUniformLocations[location].index];
}
-LinkedUniform *Program::getUniformByName(const std::string &name) const
+GLint Program::getUniformLocation(const std::string &name) const
{
- return mProgram->getUniformByName(name);
+ return mData.getUniformLocation(name);
}
-GLint Program::getUniformLocation(const std::string &name)
+GLuint Program::getUniformIndex(const std::string &name) const
{
- return mProgram->getUniformLocation(name);
-}
-
-GLuint Program::getUniformIndex(const std::string &name)
-{
- return mProgram->getUniformIndex(name);
+ return mData.getUniformIndex(name);
}
void Program::setUniform1fv(GLint location, GLsizei count, const GLfloat *v)
{
+ setUniformInternal(location, count * 1, v);
mProgram->setUniform1fv(location, count, v);
}
void Program::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
{
+ setUniformInternal(location, count * 2, v);
mProgram->setUniform2fv(location, count, v);
}
void Program::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
{
+ setUniformInternal(location, count * 3, v);
mProgram->setUniform3fv(location, count, v);
}
void Program::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
{
+ setUniformInternal(location, count * 4, v);
mProgram->setUniform4fv(location, count, v);
}
void Program::setUniform1iv(GLint location, GLsizei count, const GLint *v)
{
+ setUniformInternal(location, count * 1, v);
mProgram->setUniform1iv(location, count, v);
}
void Program::setUniform2iv(GLint location, GLsizei count, const GLint *v)
{
+ setUniformInternal(location, count * 2, v);
mProgram->setUniform2iv(location, count, v);
}
void Program::setUniform3iv(GLint location, GLsizei count, const GLint *v)
{
+ setUniformInternal(location, count * 3, v);
mProgram->setUniform3iv(location, count, v);
}
void Program::setUniform4iv(GLint location, GLsizei count, const GLint *v)
{
+ setUniformInternal(location, count * 4, v);
mProgram->setUniform4iv(location, count, v);
}
void Program::setUniform1uiv(GLint location, GLsizei count, const GLuint *v)
{
+ setUniformInternal(location, count * 1, v);
mProgram->setUniform1uiv(location, count, v);
}
void Program::setUniform2uiv(GLint location, GLsizei count, const GLuint *v)
{
+ setUniformInternal(location, count * 2, v);
mProgram->setUniform2uiv(location, count, v);
}
void Program::setUniform3uiv(GLint location, GLsizei count, const GLuint *v)
{
+ setUniformInternal(location, count * 3, v);
mProgram->setUniform3uiv(location, count, v);
}
void Program::setUniform4uiv(GLint location, GLsizei count, const GLuint *v)
{
+ setUniformInternal(location, count * 4, v);
mProgram->setUniform4uiv(location, count, v);
}
void Program::setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
{
+ setMatrixUniformInternal<2, 2>(location, count, transpose, v);
mProgram->setUniformMatrix2fv(location, count, transpose, v);
}
void Program::setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
{
+ setMatrixUniformInternal<3, 3>(location, count, transpose, v);
mProgram->setUniformMatrix3fv(location, count, transpose, v);
}
void Program::setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
{
+ setMatrixUniformInternal<4, 4>(location, count, transpose, v);
mProgram->setUniformMatrix4fv(location, count, transpose, v);
}
void Program::setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
{
+ setMatrixUniformInternal<2, 3>(location, count, transpose, v);
mProgram->setUniformMatrix2x3fv(location, count, transpose, v);
}
void Program::setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
{
+ setMatrixUniformInternal<2, 4>(location, count, transpose, v);
mProgram->setUniformMatrix2x4fv(location, count, transpose, v);
}
void Program::setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
{
+ setMatrixUniformInternal<3, 2>(location, count, transpose, v);
mProgram->setUniformMatrix3x2fv(location, count, transpose, v);
}
void Program::setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
{
+ setMatrixUniformInternal<3, 4>(location, count, transpose, v);
mProgram->setUniformMatrix3x4fv(location, count, transpose, v);
}
void Program::setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
{
+ setMatrixUniformInternal<4, 2>(location, count, transpose, v);
mProgram->setUniformMatrix4x2fv(location, count, transpose, v);
}
void Program::setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
{
+ setMatrixUniformInternal<4, 3>(location, count, transpose, v);
mProgram->setUniformMatrix4x3fv(location, count, transpose, v);
}
-void Program::getUniformfv(GLint location, GLfloat *v)
-{
- mProgram->getUniformfv(location, v);
-}
-
-void Program::getUniformiv(GLint location, GLint *v)
+void Program::getUniformfv(GLint location, GLfloat *v) const
{
- mProgram->getUniformiv(location, v);
+ getUniformInternal(location, v);
}
-void Program::getUniformuiv(GLint location, GLuint *v)
+void Program::getUniformiv(GLint location, GLint *v) const
{
- mProgram->getUniformuiv(location, v);
+ getUniformInternal(location, v);
}
-// Applies all the uniforms set for this program object to the renderer
-Error Program::applyUniforms()
+void Program::getUniformuiv(GLint location, GLuint *v) const
{
- return mProgram->applyUniforms();
-}
-
-Error Program::applyUniformBuffers(const gl::Data &data)
-{
- return mProgram->applyUniformBuffers(data, mUniformBlockBindings);
+ getUniformInternal(location, v);
}
void Program::flagForDeletion()
@@ -1019,22 +1288,91 @@ bool Program::isFlaggedForDeletion() const
void Program::validate(const Caps &caps)
{
mInfoLog.reset();
- mValidated = false;
if (mLinked)
{
- applyUniforms();
- mValidated = mProgram->validateSamplers(&mInfoLog, caps);
+ mValidated = (mProgram->validate(caps, &mInfoLog) == GL_TRUE);
}
else
{
- mInfoLog.append("Program has not been successfully linked.");
+ mInfoLog << "Program has not been successfully linked.";
}
}
bool Program::validateSamplers(InfoLog *infoLog, const Caps &caps)
{
- return mProgram->validateSamplers(infoLog, caps);
+ // Skip cache if we're using an infolog, so we get the full error.
+ // Also skip the cache if the sample mapping has changed, or if we haven't ever validated.
+ if (infoLog == nullptr && mCachedValidateSamplersResult.valid())
+ {
+ return mCachedValidateSamplersResult.value();
+ }
+
+ if (mTextureUnitTypesCache.empty())
+ {
+ mTextureUnitTypesCache.resize(caps.maxCombinedTextureImageUnits, GL_NONE);
+ }
+ else
+ {
+ std::fill(mTextureUnitTypesCache.begin(), mTextureUnitTypesCache.end(), GL_NONE);
+ }
+
+ // if any two active samplers in a program are of different types, but refer to the same
+ // texture image unit, and this is the current program, then ValidateProgram will fail, and
+ // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
+ for (unsigned int samplerIndex = mSamplerUniformRange.start;
+ samplerIndex < mSamplerUniformRange.end; ++samplerIndex)
+ {
+ const LinkedUniform &uniform = mData.mUniforms[samplerIndex];
+ ASSERT(uniform.isSampler());
+
+ if (!uniform.staticUse)
+ continue;
+
+ const GLuint *dataPtr = reinterpret_cast<const GLuint *>(uniform.getDataPtrToElement(0));
+ GLenum textureType = SamplerTypeToTextureType(uniform.type);
+
+ for (unsigned int arrayElement = 0; arrayElement < uniform.elementCount(); ++arrayElement)
+ {
+ GLuint textureUnit = dataPtr[arrayElement];
+
+ if (textureUnit >= caps.maxCombinedTextureImageUnits)
+ {
+ if (infoLog)
+ {
+ (*infoLog) << "Sampler uniform (" << textureUnit
+ << ") exceeds GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS ("
+ << caps.maxCombinedTextureImageUnits << ")";
+ }
+
+ mCachedValidateSamplersResult = false;
+ return false;
+ }
+
+ if (mTextureUnitTypesCache[textureUnit] != GL_NONE)
+ {
+ if (textureType != mTextureUnitTypesCache[textureUnit])
+ {
+ if (infoLog)
+ {
+ (*infoLog) << "Samplers of conflicting types refer to the same texture "
+ "image unit ("
+ << textureUnit << ").";
+ }
+
+ mCachedValidateSamplersResult = false;
+ return false;
+ }
+ }
+ else
+ {
+ mTextureUnitTypesCache[textureUnit] = textureType;
+ }
+ }
+ }
+
+ mCachedValidateSamplersResult = true;
+ return true;
}
bool Program::isValidated() const
@@ -1042,29 +1380,25 @@ bool Program::isValidated() const
return mValidated;
}
-void Program::updateSamplerMapping()
+GLuint Program::getActiveUniformBlockCount() const
{
- return mProgram->updateSamplerMapping();
-}
-
-GLuint Program::getActiveUniformBlockCount()
-{
- return mProgram->getUniformBlocks().size();
+ return static_cast<GLuint>(mData.mUniformBlocks.size());
}
void Program::getActiveUniformBlockName(GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) const
{
- ASSERT(uniformBlockIndex < mProgram->getUniformBlocks().size()); // index must be smaller than getActiveUniformBlockCount()
+ ASSERT(uniformBlockIndex <
+ mData.mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount()
- const UniformBlock &uniformBlock = *mProgram->getUniformBlocks()[uniformBlockIndex];
+ const UniformBlock &uniformBlock = mData.mUniformBlocks[uniformBlockIndex];
if (bufSize > 0)
{
std::string string = uniformBlock.name;
- if (uniformBlock.isArrayElement())
+ if (uniformBlock.isArray)
{
- string += ArrayString(uniformBlock.elementIndex);
+ string += ArrayString(uniformBlock.arrayElement);
}
strncpy(uniformBlockName, string.c_str(), bufSize);
@@ -1072,16 +1406,17 @@ void Program::getActiveUniformBlockName(GLuint uniformBlockIndex, GLsizei bufSiz
if (length)
{
- *length = strlen(uniformBlockName);
+ *length = static_cast<GLsizei>(strlen(uniformBlockName));
}
}
}
void Program::getActiveUniformBlockiv(GLuint uniformBlockIndex, GLenum pname, GLint *params) const
{
- ASSERT(uniformBlockIndex < mProgram->getUniformBlocks().size()); // index must be smaller than getActiveUniformBlockCount()
+ ASSERT(uniformBlockIndex <
+ mData.mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount()
- const UniformBlock &uniformBlock = *mProgram->getUniformBlocks()[uniformBlockIndex];
+ const UniformBlock &uniformBlock = mData.mUniformBlocks[uniformBlockIndex];
switch (pname)
{
@@ -1089,7 +1424,8 @@ void Program::getActiveUniformBlockiv(GLuint uniformBlockIndex, GLenum pname, GL
*params = static_cast<GLint>(uniformBlock.dataSize);
break;
case GL_UNIFORM_BLOCK_NAME_LENGTH:
- *params = static_cast<GLint>(uniformBlock.name.size() + 1 + (uniformBlock.isArrayElement() ? 3 : 0));
+ *params =
+ static_cast<GLint>(uniformBlock.name.size() + 1 + (uniformBlock.isArray ? 3 : 0));
break;
case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
*params = static_cast<GLint>(uniformBlock.memberUniformIndexes.size());
@@ -1103,31 +1439,31 @@ void Program::getActiveUniformBlockiv(GLuint uniformBlockIndex, GLenum pname, GL
}
break;
case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
- *params = static_cast<GLint>(uniformBlock.isReferencedByVertexShader());
+ *params = static_cast<GLint>(uniformBlock.vertexStaticUse);
break;
case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
- *params = static_cast<GLint>(uniformBlock.isReferencedByFragmentShader());
+ *params = static_cast<GLint>(uniformBlock.fragmentStaticUse);
break;
default: UNREACHABLE();
}
}
-GLint Program::getActiveUniformBlockMaxLength()
+GLint Program::getActiveUniformBlockMaxLength() const
{
int maxLength = 0;
if (mLinked)
{
- unsigned int numUniformBlocks = mProgram->getUniformBlocks().size();
+ unsigned int numUniformBlocks = static_cast<unsigned int>(mData.mUniformBlocks.size());
for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < numUniformBlocks; uniformBlockIndex++)
{
- const UniformBlock &uniformBlock = *mProgram->getUniformBlocks()[uniformBlockIndex];
+ const UniformBlock &uniformBlock = mData.mUniformBlocks[uniformBlockIndex];
if (!uniformBlock.name.empty())
{
- const int length = uniformBlock.name.length() + 1;
+ const int length = static_cast<int>(uniformBlock.name.length()) + 1;
// Counting in "[0]".
- const int arrayLength = (uniformBlock.isArrayElement() ? 3 : 0);
+ const int arrayLength = (uniformBlock.isArray ? 3 : 0);
maxLength = std::max(length + arrayLength, maxLength);
}
@@ -1137,51 +1473,73 @@ GLint Program::getActiveUniformBlockMaxLength()
return maxLength;
}
-GLuint Program::getUniformBlockIndex(const std::string &name)
+GLuint Program::getUniformBlockIndex(const std::string &name) const
{
- return mProgram->getUniformBlockIndex(name);
+ size_t subscript = GL_INVALID_INDEX;
+ std::string baseName = gl::ParseUniformName(name, &subscript);
+
+ unsigned int numUniformBlocks = static_cast<unsigned int>(mData.mUniformBlocks.size());
+ for (unsigned int blockIndex = 0; blockIndex < numUniformBlocks; blockIndex++)
+ {
+ const gl::UniformBlock &uniformBlock = mData.mUniformBlocks[blockIndex];
+ if (uniformBlock.name == baseName)
+ {
+ const bool arrayElementZero =
+ (subscript == GL_INVALID_INDEX &&
+ (!uniformBlock.isArray || uniformBlock.arrayElement == 0));
+ if (subscript == uniformBlock.arrayElement || arrayElementZero)
+ {
+ return blockIndex;
+ }
+ }
+ }
+
+ return GL_INVALID_INDEX;
}
-const UniformBlock *Program::getUniformBlockByIndex(GLuint index) const
+const UniformBlock &Program::getUniformBlockByIndex(GLuint index) const
{
- return mProgram->getUniformBlockByIndex(index);
+ ASSERT(index < static_cast<GLuint>(mData.mUniformBlocks.size()));
+ return mData.mUniformBlocks[index];
}
void Program::bindUniformBlock(GLuint uniformBlockIndex, GLuint uniformBlockBinding)
{
- mUniformBlockBindings[uniformBlockIndex] = uniformBlockBinding;
+ mData.mUniformBlockBindings[uniformBlockIndex] = uniformBlockBinding;
+ mProgram->setUniformBlockBinding(uniformBlockIndex, uniformBlockBinding);
}
GLuint Program::getUniformBlockBinding(GLuint uniformBlockIndex) const
{
- return mUniformBlockBindings[uniformBlockIndex];
+ return mData.getUniformBlockBinding(uniformBlockIndex);
}
void Program::resetUniformBlockBindings()
{
for (unsigned int blockId = 0; blockId < IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS; blockId++)
{
- mUniformBlockBindings[blockId] = 0;
+ mData.mUniformBlockBindings[blockId] = 0;
}
+ mData.mActiveUniformBlockBindings.reset();
}
void Program::setTransformFeedbackVaryings(GLsizei count, const GLchar *const *varyings, GLenum bufferMode)
{
- mTransformFeedbackVaryings.resize(count);
+ mData.mTransformFeedbackVaryingNames.resize(count);
for (GLsizei i = 0; i < count; i++)
{
- mTransformFeedbackVaryings[i] = varyings[i];
+ mData.mTransformFeedbackVaryingNames[i] = varyings[i];
}
- mTransformFeedbackBufferMode = bufferMode;
+ mData.mTransformFeedbackBufferMode = bufferMode;
}
void Program::getTransformFeedbackVarying(GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name) const
{
if (mLinked)
{
- ASSERT(index < mProgram->getTransformFeedbackLinkedVaryings().size());
- const LinkedVarying &varying = mProgram->getTransformFeedbackLinkedVaryings()[index];
+ ASSERT(index < mData.mTransformFeedbackVaryingVars.size());
+ const sh::Varying &varying = mData.mTransformFeedbackVaryingVars[index];
GLsizei lastNameIdx = std::min(bufSize - 1, static_cast<GLsizei>(varying.name.length()));
if (length)
{
@@ -1189,7 +1547,7 @@ void Program::getTransformFeedbackVarying(GLuint index, GLsizei bufSize, GLsizei
}
if (size)
{
- *size = varying.size;
+ *size = varying.elementCount();
}
if (type)
{
@@ -1207,7 +1565,7 @@ GLsizei Program::getTransformFeedbackVaryingCount() const
{
if (mLinked)
{
- return static_cast<GLsizei>(mProgram->getTransformFeedbackLinkedVaryings().size());
+ return static_cast<GLsizei>(mData.mTransformFeedbackVaryingVars.size());
}
else
{
@@ -1220,9 +1578,8 @@ GLsizei Program::getTransformFeedbackVaryingMaxLength() const
if (mLinked)
{
GLsizei maxSize = 0;
- for (size_t i = 0; i < mProgram->getTransformFeedbackLinkedVaryings().size(); i++)
+ for (const sh::Varying &varying : mData.mTransformFeedbackVaryingVars)
{
- const LinkedVarying &varying = mProgram->getTransformFeedbackLinkedVaryings()[i];
maxSize = std::max(maxSize, static_cast<GLsizei>(varying.name.length() + 1));
}
@@ -1236,64 +1593,123 @@ GLsizei Program::getTransformFeedbackVaryingMaxLength() const
GLenum Program::getTransformFeedbackBufferMode() const
{
- return mTransformFeedbackBufferMode;
+ return mData.mTransformFeedbackBufferMode;
}
-bool Program::linkVaryings(InfoLog &infoLog, Shader *fragmentShader, Shader *vertexShader)
+// static
+bool Program::linkVaryings(InfoLog &infoLog,
+ const Shader *vertexShader,
+ const Shader *fragmentShader)
{
- std::vector<PackedVarying> &fragmentVaryings = fragmentShader->getVaryings();
- std::vector<PackedVarying> &vertexVaryings = vertexShader->getVaryings();
+ const std::vector<sh::Varying> &vertexVaryings = vertexShader->getVaryings();
+ const std::vector<sh::Varying> &fragmentVaryings = fragmentShader->getVaryings();
- for (size_t fragVaryingIndex = 0; fragVaryingIndex < fragmentVaryings.size(); fragVaryingIndex++)
+ for (const sh::Varying &output : fragmentVaryings)
{
- PackedVarying *input = &fragmentVaryings[fragVaryingIndex];
bool matched = false;
// Built-in varyings obey special rules
- if (input->isBuiltIn())
+ if (output.isBuiltIn())
{
continue;
}
- for (size_t vertVaryingIndex = 0; vertVaryingIndex < vertexVaryings.size(); vertVaryingIndex++)
+ for (const sh::Varying &input : vertexVaryings)
{
- PackedVarying *output = &vertexVaryings[vertVaryingIndex];
- if (output->name == input->name)
+ if (output.name == input.name)
{
- if (!linkValidateVaryings(infoLog, output->name, *input, *output))
+ ASSERT(!input.isBuiltIn());
+ if (!linkValidateVaryings(infoLog, output.name, input, output))
{
return false;
}
- output->registerIndex = input->registerIndex;
- output->columnIndex = input->columnIndex;
-
matched = true;
break;
}
}
// We permit unmatched, unreferenced varyings
- if (!matched && input->staticUse)
+ if (!matched && output.staticUse)
{
- infoLog.append("Fragment varying %s does not match any vertex varying", input->name.c_str());
+ infoLog << "Fragment varying " << output.name << " does not match any vertex varying";
return false;
}
}
+ // TODO(jmadill): verify no unmatched vertex varyings?
+
return true;
}
+bool Program::linkUniforms(gl::InfoLog &infoLog, const gl::Caps &caps)
+{
+ const std::vector<sh::Uniform> &vertexUniforms = mData.mAttachedVertexShader->getUniforms();
+ const std::vector<sh::Uniform> &fragmentUniforms = mData.mAttachedFragmentShader->getUniforms();
+
+ // Check that uniforms defined in the vertex and fragment shaders are identical
+ std::map<std::string, LinkedUniform> linkedUniforms;
+
+ for (const sh::Uniform &vertexUniform : vertexUniforms)
+ {
+ linkedUniforms[vertexUniform.name] = LinkedUniform(vertexUniform);
+ }
+
+ for (const sh::Uniform &fragmentUniform : fragmentUniforms)
+ {
+ auto entry = linkedUniforms.find(fragmentUniform.name);
+ if (entry != linkedUniforms.end())
+ {
+ LinkedUniform *vertexUniform = &entry->second;
+ const std::string &uniformName = "uniform '" + vertexUniform->name + "'";
+ if (!linkValidateUniforms(infoLog, uniformName, *vertexUniform, fragmentUniform))
+ {
+ return false;
+ }
+ }
+ }
+
+ // Flatten the uniforms list (nested fields) into a simple list (no nesting).
+ // Also check the maximum uniform vector and sampler counts.
+ if (!flattenUniformsAndCheckCaps(caps, infoLog))
+ {
+ return false;
+ }
+
+ indexUniforms();
+
+ return true;
+}
+
+void Program::indexUniforms()
+{
+ for (size_t uniformIndex = 0; uniformIndex < mData.mUniforms.size(); uniformIndex++)
+ {
+ const gl::LinkedUniform &uniform = mData.mUniforms[uniformIndex];
+
+ for (unsigned int arrayIndex = 0; arrayIndex < uniform.elementCount(); arrayIndex++)
+ {
+ if (!uniform.isBuiltIn())
+ {
+ // Assign in-order uniform locations
+ mData.mUniformLocations.push_back(gl::VariableLocation(
+ uniform.name, arrayIndex, static_cast<unsigned int>(uniformIndex)));
+ }
+ }
+ }
+}
+
bool Program::linkValidateInterfaceBlockFields(InfoLog &infoLog, const std::string &uniformName, const sh::InterfaceBlockField &vertexUniform, const sh::InterfaceBlockField &fragmentUniform)
{
- if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, true))
+ // We don't validate precision on UBO fields. See resolution of Khronos bug 10287.
+ if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, false))
{
return false;
}
if (vertexUniform.isRowMajorLayout != fragmentUniform.isRowMajorLayout)
{
- infoLog.append("Matrix packings for %s differ between vertex and fragment shaders", uniformName.c_str());
+ infoLog << "Matrix packings for " << uniformName << " differ between vertex and fragment shaders";
return false;
}
@@ -1301,143 +1717,168 @@ bool Program::linkValidateInterfaceBlockFields(InfoLog &infoLog, const std::stri
}
// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
-bool Program::linkAttributes(InfoLog &infoLog, const AttributeBindings &attributeBindings, const Shader *vertexShader)
+bool Program::linkAttributes(const gl::Data &data,
+ InfoLog &infoLog,
+ const AttributeBindings &attributeBindings,
+ const Shader *vertexShader)
{
unsigned int usedLocations = 0;
- const std::vector<sh::Attribute> &shaderAttributes = vertexShader->getActiveAttributes();
+ mData.mAttributes = vertexShader->getActiveAttributes();
+ GLuint maxAttribs = data.caps->maxVertexAttributes;
- // Link attributes that have a binding location
- for (unsigned int attributeIndex = 0; attributeIndex < shaderAttributes.size(); attributeIndex++)
+ // TODO(jmadill): handle aliasing robustly
+ if (mData.mAttributes.size() > maxAttribs)
{
- const sh::Attribute &attribute = shaderAttributes[attributeIndex];
+ infoLog << "Too many vertex attributes.";
+ return false;
+ }
- ASSERT(attribute.staticUse);
+ std::vector<sh::Attribute *> usedAttribMap(data.caps->maxVertexAttributes, nullptr);
- const int location = attribute.location == -1 ? attributeBindings.getAttributeBinding(attribute.name) : attribute.location;
+ // Link attributes that have a binding location
+ for (sh::Attribute &attribute : mData.mAttributes)
+ {
+ // TODO(jmadill): do staticUse filtering step here, or not at all
+ ASSERT(attribute.staticUse);
- mProgram->getShaderAttributes()[attributeIndex] = attribute;
+ int bindingLocation = attributeBindings.getAttributeBinding(attribute.name);
+ if (attribute.location == -1 && bindingLocation != -1)
+ {
+ attribute.location = bindingLocation;
+ }
- if (location != -1) // Set by glBindAttribLocation or by location layout qualifier
+ if (attribute.location != -1)
{
- const int rows = VariableRegisterCount(attribute.type);
+ // Location is set by glBindAttribLocation or by location layout qualifier
+ const int regs = VariableRegisterCount(attribute.type);
- if (rows + location > MAX_VERTEX_ATTRIBS)
+ if (static_cast<GLuint>(regs + attribute.location) > maxAttribs)
{
- infoLog.append("Active attribute (%s) at location %d is too big to fit", attribute.name.c_str(), location);
+ infoLog << "Active attribute (" << attribute.name << ") at location "
+ << attribute.location << " is too big to fit";
return false;
}
- for (int row = 0; row < rows; row++)
+ for (int reg = 0; reg < regs; reg++)
{
- const int rowLocation = location + row;
- sh::ShaderVariable &linkedAttribute = mLinkedAttribute[rowLocation];
+ const int regLocation = attribute.location + reg;
+ sh::ShaderVariable *linkedAttribute = usedAttribMap[regLocation];
// In GLSL 3.00, attribute aliasing produces a link error
- // In GLSL 1.00, attribute aliasing is allowed
- if (mProgram->getShaderVersion() >= 300)
+ // In GLSL 1.00, attribute aliasing is allowed, but ANGLE currently has a bug
+ if (linkedAttribute)
{
- if (!linkedAttribute.name.empty())
+ // TODO(jmadill): fix aliasing on ES2
+ // if (mProgram->getShaderVersion() >= 300)
{
- infoLog.append("Attribute '%s' aliases attribute '%s' at location %d", attribute.name.c_str(), linkedAttribute.name.c_str(), rowLocation);
+ infoLog << "Attribute '" << attribute.name << "' aliases attribute '"
+ << linkedAttribute->name << "' at location " << regLocation;
return false;
}
}
+ else
+ {
+ usedAttribMap[regLocation] = &attribute;
+ }
- linkedAttribute = attribute;
- usedLocations |= 1 << rowLocation;
+ usedLocations |= 1 << regLocation;
}
}
}
// Link attributes that don't have a binding location
- for (unsigned int attributeIndex = 0; attributeIndex < shaderAttributes.size(); attributeIndex++)
+ for (sh::Attribute &attribute : mData.mAttributes)
{
- const sh::Attribute &attribute = shaderAttributes[attributeIndex];
-
ASSERT(attribute.staticUse);
- const int location = attribute.location == -1 ? attributeBindings.getAttributeBinding(attribute.name) : attribute.location;
-
- if (location == -1) // Not set by glBindAttribLocation or by location layout qualifier
+ // Not set by glBindAttribLocation or by location layout qualifier
+ if (attribute.location == -1)
{
- int rows = VariableRegisterCount(attribute.type);
- int availableIndex = AllocateFirstFreeBits(&usedLocations, rows, MAX_VERTEX_ATTRIBS);
+ int regs = VariableRegisterCount(attribute.type);
+ int availableIndex = AllocateFirstFreeBits(&usedLocations, regs, maxAttribs);
- if (availableIndex == -1 || availableIndex + rows > MAX_VERTEX_ATTRIBS)
+ if (availableIndex == -1 || static_cast<GLuint>(availableIndex + regs) > maxAttribs)
{
- infoLog.append("Too many active attributes (%s)", attribute.name.c_str());
-
- return false; // Fail to link
+ infoLog << "Too many active attributes (" << attribute.name << ")";
+ return false;
}
- mLinkedAttribute[availableIndex] = attribute;
+ attribute.location = availableIndex;
}
}
- for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; )
+ for (const sh::Attribute &attribute : mData.mAttributes)
{
- int index = vertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].name);
- int rows = VariableRegisterCount(mLinkedAttribute[attributeIndex].type);
+ ASSERT(attribute.staticUse);
+ ASSERT(attribute.location != -1);
+ int regs = VariableRegisterCount(attribute.type);
- for (int r = 0; r < rows; r++)
+ for (int r = 0; r < regs; r++)
{
- mProgram->getSemanticIndexes()[attributeIndex++] = index++;
+ mData.mActiveAttribLocationsMask.set(attribute.location + r);
}
}
return true;
}
-bool Program::linkUniformBlocks(InfoLog &infoLog, const Shader &vertexShader, const Shader &fragmentShader, const Caps &caps)
+bool Program::linkUniformBlocks(InfoLog &infoLog, const Caps &caps)
{
+ const Shader &vertexShader = *mData.mAttachedVertexShader;
+ const Shader &fragmentShader = *mData.mAttachedFragmentShader;
+
const std::vector<sh::InterfaceBlock> &vertexInterfaceBlocks = vertexShader.getInterfaceBlocks();
const std::vector<sh::InterfaceBlock> &fragmentInterfaceBlocks = fragmentShader.getInterfaceBlocks();
+
// Check that interface blocks defined in the vertex and fragment shaders are identical
typedef std::map<std::string, const sh::InterfaceBlock*> UniformBlockMap;
UniformBlockMap linkedUniformBlocks;
- for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++)
+
+ GLuint vertexBlockCount = 0;
+ for (const sh::InterfaceBlock &vertexInterfaceBlock : vertexInterfaceBlocks)
{
- const sh::InterfaceBlock &vertexInterfaceBlock = vertexInterfaceBlocks[blockIndex];
linkedUniformBlocks[vertexInterfaceBlock.name] = &vertexInterfaceBlock;
- }
- for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++)
- {
- const sh::InterfaceBlock &fragmentInterfaceBlock = fragmentInterfaceBlocks[blockIndex];
- UniformBlockMap::const_iterator entry = linkedUniformBlocks.find(fragmentInterfaceBlock.name);
- if (entry != linkedUniformBlocks.end())
+
+ // Note: shared and std140 layouts are always considered active
+ if (vertexInterfaceBlock.staticUse || vertexInterfaceBlock.layout != sh::BLOCKLAYOUT_PACKED)
{
- const sh::InterfaceBlock &vertexInterfaceBlock = *entry->second;
- if (!areMatchingInterfaceBlocks(infoLog, vertexInterfaceBlock, fragmentInterfaceBlock))
+ if (++vertexBlockCount > caps.maxVertexUniformBlocks)
{
+ infoLog << "Vertex shader uniform block count exceed GL_MAX_VERTEX_UNIFORM_BLOCKS ("
+ << caps.maxVertexUniformBlocks << ")";
return false;
}
}
}
- for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++)
+
+ GLuint fragmentBlockCount = 0;
+ for (const sh::InterfaceBlock &fragmentInterfaceBlock : fragmentInterfaceBlocks)
{
- const sh::InterfaceBlock &interfaceBlock = vertexInterfaceBlocks[blockIndex];
- // Note: shared and std140 layouts are always considered active
- if (interfaceBlock.staticUse || interfaceBlock.layout != sh::BLOCKLAYOUT_PACKED)
+ auto entry = linkedUniformBlocks.find(fragmentInterfaceBlock.name);
+ if (entry != linkedUniformBlocks.end())
{
- if (!mProgram->defineUniformBlock(infoLog, vertexShader, interfaceBlock, caps))
+ const sh::InterfaceBlock &vertexInterfaceBlock = *entry->second;
+ if (!areMatchingInterfaceBlocks(infoLog, vertexInterfaceBlock, fragmentInterfaceBlock))
{
return false;
}
}
- }
- for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++)
- {
- const sh::InterfaceBlock &interfaceBlock = fragmentInterfaceBlocks[blockIndex];
+
// Note: shared and std140 layouts are always considered active
- if (interfaceBlock.staticUse || interfaceBlock.layout != sh::BLOCKLAYOUT_PACKED)
+ if (fragmentInterfaceBlock.staticUse ||
+ fragmentInterfaceBlock.layout != sh::BLOCKLAYOUT_PACKED)
{
- if (!mProgram->defineUniformBlock(infoLog, fragmentShader, interfaceBlock, caps))
+ if (++fragmentBlockCount > caps.maxFragmentUniformBlocks)
{
+ infoLog
+ << "Fragment shader uniform block count exceed GL_MAX_FRAGMENT_UNIFORM_BLOCKS ("
+ << caps.maxFragmentUniformBlocks << ")";
return false;
}
}
}
+
return true;
}
@@ -1448,28 +1889,34 @@ bool Program::areMatchingInterfaceBlocks(gl::InfoLog &infoLog, const sh::Interfa
// validate blocks for the same member types
if (vertexInterfaceBlock.fields.size() != fragmentInterfaceBlock.fields.size())
{
- infoLog.append("Types for interface block '%s' differ between vertex and fragment shaders", blockName);
+ infoLog << "Types for interface block '" << blockName
+ << "' differ between vertex and fragment shaders";
return false;
}
if (vertexInterfaceBlock.arraySize != fragmentInterfaceBlock.arraySize)
{
- infoLog.append("Array sizes differ for interface block '%s' between vertex and fragment shaders", blockName);
+ infoLog << "Array sizes differ for interface block '" << blockName
+ << "' between vertex and fragment shaders";
return false;
}
if (vertexInterfaceBlock.layout != fragmentInterfaceBlock.layout || vertexInterfaceBlock.isRowMajorLayout != fragmentInterfaceBlock.isRowMajorLayout)
{
- infoLog.append("Layout qualifiers differ for interface block '%s' between vertex and fragment shaders", blockName);
+ infoLog << "Layout qualifiers differ for interface block '" << blockName
+ << "' between vertex and fragment shaders";
return false;
}
- const unsigned int numBlockMembers = vertexInterfaceBlock.fields.size();
+ const unsigned int numBlockMembers =
+ static_cast<unsigned int>(vertexInterfaceBlock.fields.size());
for (unsigned int blockMemberIndex = 0; blockMemberIndex < numBlockMembers; blockMemberIndex++)
{
const sh::InterfaceBlockField &vertexMember = vertexInterfaceBlock.fields[blockMemberIndex];
const sh::InterfaceBlockField &fragmentMember = fragmentInterfaceBlock.fields[blockMemberIndex];
if (vertexMember.name != fragmentMember.name)
{
- infoLog.append("Name mismatch for field %d of interface block '%s': (in vertex: '%s', in fragment: '%s')",
- blockMemberIndex, blockName, vertexMember.name.c_str(), fragmentMember.name.c_str());
+ infoLog << "Name mismatch for field " << blockMemberIndex
+ << " of interface block '" << blockName
+ << "': (in vertex: '" << vertexMember.name
+ << "', in fragment: '" << fragmentMember.name << "')";
return false;
}
std::string memberName = "interface block '" + vertexInterfaceBlock.name + "' member '" + vertexMember.name + "'";
@@ -1486,26 +1933,26 @@ bool Program::linkValidateVariablesBase(InfoLog &infoLog, const std::string &var
{
if (vertexVariable.type != fragmentVariable.type)
{
- infoLog.append("Types for %s differ between vertex and fragment shaders", variableName.c_str());
+ infoLog << "Types for " << variableName << " differ between vertex and fragment shaders";
return false;
}
if (vertexVariable.arraySize != fragmentVariable.arraySize)
{
- infoLog.append("Array sizes for %s differ between vertex and fragment shaders", variableName.c_str());
+ infoLog << "Array sizes for " << variableName << " differ between vertex and fragment shaders";
return false;
}
if (validatePrecision && vertexVariable.precision != fragmentVariable.precision)
{
- infoLog.append("Precisions for %s differ between vertex and fragment shaders", variableName.c_str());
+ infoLog << "Precisions for " << variableName << " differ between vertex and fragment shaders";
return false;
}
if (vertexVariable.fields.size() != fragmentVariable.fields.size())
{
- infoLog.append("Structure lengths for %s differ between vertex and fragment shaders", variableName.c_str());
+ infoLog << "Structure lengths for " << variableName << " differ between vertex and fragment shaders";
return false;
}
- const unsigned int numMembers = vertexVariable.fields.size();
+ const unsigned int numMembers = static_cast<unsigned int>(vertexVariable.fields.size());
for (unsigned int memberIndex = 0; memberIndex < numMembers; memberIndex++)
{
const sh::ShaderVariable &vertexMember = vertexVariable.fields[memberIndex];
@@ -1513,9 +1960,10 @@ bool Program::linkValidateVariablesBase(InfoLog &infoLog, const std::string &var
if (vertexMember.name != fragmentMember.name)
{
- infoLog.append("Name mismatch for field '%d' of %s: (in vertex: '%s', in fragment: '%s')",
- memberIndex, variableName.c_str(),
- vertexMember.name.c_str(), fragmentMember.name.c_str());
+ infoLog << "Name mismatch for field '" << memberIndex
+ << "' of " << variableName
+ << ": (in vertex: '" << vertexMember.name
+ << "', in fragment: '" << fragmentMember.name << "')";
return false;
}
@@ -1533,7 +1981,13 @@ bool Program::linkValidateVariablesBase(InfoLog &infoLog, const std::string &var
bool Program::linkValidateUniforms(InfoLog &infoLog, const std::string &uniformName, const sh::Uniform &vertexUniform, const sh::Uniform &fragmentUniform)
{
- if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, true))
+#if ANGLE_PROGRAM_LINK_VALIDATE_UNIFORM_PRECISION == ANGLE_ENABLED
+ const bool validatePrecision = true;
+#else
+ const bool validatePrecision = false;
+#endif
+
+ if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, validatePrecision))
{
return false;
}
@@ -1550,68 +2004,530 @@ bool Program::linkValidateVaryings(InfoLog &infoLog, const std::string &varyingN
if (!sh::InterpolationTypesMatch(vertexVarying.interpolation, fragmentVarying.interpolation))
{
- infoLog.append("Interpolation types for %s differ between vertex and fragment shaders", varyingName.c_str());
+ infoLog << "Interpolation types for " << varyingName << " differ between vertex and fragment shaders";
return false;
}
return true;
}
-bool Program::gatherTransformFeedbackLinkedVaryings(InfoLog &infoLog, const std::vector<LinkedVarying> &linkedVaryings,
- const std::vector<std::string> &transformFeedbackVaryingNames,
- GLenum transformFeedbackBufferMode,
- std::vector<LinkedVarying> *outTransformFeedbackLinkedVaryings,
- const Caps &caps) const
+bool Program::linkValidateTransformFeedback(InfoLog &infoLog,
+ const std::vector<const sh::Varying *> &varyings,
+ const Caps &caps) const
{
size_t totalComponents = 0;
- // Gather the linked varyings that are used for transform feedback, they should all exist.
- outTransformFeedbackLinkedVaryings->clear();
- for (size_t i = 0; i < transformFeedbackVaryingNames.size(); i++)
+ std::set<std::string> uniqueNames;
+
+ for (const std::string &tfVaryingName : mData.mTransformFeedbackVaryingNames)
{
bool found = false;
- for (size_t j = 0; j < linkedVaryings.size(); j++)
+ for (const sh::Varying *varying : varyings)
{
- if (transformFeedbackVaryingNames[i] == linkedVaryings[j].name)
+ if (tfVaryingName == varying->name)
{
- for (size_t k = 0; k < outTransformFeedbackLinkedVaryings->size(); k++)
+ if (uniqueNames.count(tfVaryingName) > 0)
{
- if (outTransformFeedbackLinkedVaryings->at(k).name == linkedVaryings[j].name)
- {
- infoLog.append("Two transform feedback varyings specify the same output variable (%s).", linkedVaryings[j].name.c_str());
- return false;
- }
+ infoLog << "Two transform feedback varyings specify the same output variable ("
+ << tfVaryingName << ").";
+ return false;
}
+ uniqueNames.insert(tfVaryingName);
- size_t componentCount = linkedVaryings[j].semanticIndexCount * 4;
- if (transformFeedbackBufferMode == GL_SEPARATE_ATTRIBS &&
+ if (varying->isArray())
+ {
+ infoLog << "Capture of arrays is undefined and not supported.";
+ return false;
+ }
+
+ // TODO(jmadill): Investigate implementation limits on D3D11
+ size_t componentCount = gl::VariableComponentCount(varying->type);
+ if (mData.mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS &&
componentCount > caps.maxTransformFeedbackSeparateComponents)
{
- infoLog.append("Transform feedback varying's %s components (%u) exceed the maximum separate components (%u).",
- linkedVaryings[j].name.c_str(), componentCount, caps.maxTransformFeedbackSeparateComponents);
+ infoLog << "Transform feedback varying's " << varying->name << " components ("
+ << componentCount << ") exceed the maximum separate components ("
+ << caps.maxTransformFeedbackSeparateComponents << ").";
return false;
}
totalComponents += componentCount;
-
- outTransformFeedbackLinkedVaryings->push_back(linkedVaryings[j]);
found = true;
break;
}
}
+ if (tfVaryingName.find('[') != std::string::npos)
+ {
+ infoLog << "Capture of array elements is undefined and not supported.";
+ return false;
+ }
+
// All transform feedback varyings are expected to exist since packVaryings checks for them.
ASSERT(found);
+ UNUSED_ASSERTION_VARIABLE(found);
}
- if (transformFeedbackBufferMode == GL_INTERLEAVED_ATTRIBS && totalComponents > caps.maxTransformFeedbackInterleavedComponents)
+ if (mData.mTransformFeedbackBufferMode == GL_INTERLEAVED_ATTRIBS &&
+ totalComponents > caps.maxTransformFeedbackInterleavedComponents)
{
- infoLog.append("Transform feedback varying total components (%u) exceed the maximum interleaved components (%u).",
- totalComponents, caps.maxTransformFeedbackInterleavedComponents);
+ infoLog << "Transform feedback varying total components (" << totalComponents
+ << ") exceed the maximum interleaved components ("
+ << caps.maxTransformFeedbackInterleavedComponents << ").";
return false;
}
return true;
}
+void Program::gatherTransformFeedbackVaryings(const std::vector<const sh::Varying *> &varyings)
+{
+ // Gather the linked varyings that are used for transform feedback, they should all exist.
+ mData.mTransformFeedbackVaryingVars.clear();
+ for (const std::string &tfVaryingName : mData.mTransformFeedbackVaryingNames)
+ {
+ for (const sh::Varying *varying : varyings)
+ {
+ if (tfVaryingName == varying->name)
+ {
+ mData.mTransformFeedbackVaryingVars.push_back(*varying);
+ break;
+ }
+ }
+ }
+}
+
+std::vector<const sh::Varying *> Program::getMergedVaryings() const
+{
+ std::set<std::string> uniqueNames;
+ std::vector<const sh::Varying *> varyings;
+
+ for (const sh::Varying &varying : mData.mAttachedVertexShader->getVaryings())
+ {
+ if (uniqueNames.count(varying.name) == 0)
+ {
+ uniqueNames.insert(varying.name);
+ varyings.push_back(&varying);
+ }
+ }
+
+ for (const sh::Varying &varying : mData.mAttachedFragmentShader->getVaryings())
+ {
+ if (uniqueNames.count(varying.name) == 0)
+ {
+ uniqueNames.insert(varying.name);
+ varyings.push_back(&varying);
+ }
+ }
+
+ return varyings;
+}
+
+void Program::linkOutputVariables()
+{
+ const Shader *fragmentShader = mData.mAttachedFragmentShader;
+ ASSERT(fragmentShader != nullptr);
+
+ // Skip this step for GLES2 shaders.
+ if (fragmentShader->getShaderVersion() == 100)
+ return;
+
+ const auto &shaderOutputVars = fragmentShader->getActiveOutputVariables();
+
+ // TODO(jmadill): any caps validation here?
+
+ for (unsigned int outputVariableIndex = 0; outputVariableIndex < shaderOutputVars.size();
+ outputVariableIndex++)
+ {
+ const sh::OutputVariable &outputVariable = shaderOutputVars[outputVariableIndex];
+
+ // Don't store outputs for gl_FragDepth, gl_FragColor, etc.
+ if (outputVariable.isBuiltIn())
+ continue;
+
+ // Since multiple output locations must be specified, use 0 for non-specified locations.
+ int baseLocation = (outputVariable.location == -1 ? 0 : outputVariable.location);
+
+ ASSERT(outputVariable.staticUse);
+
+ for (unsigned int elementIndex = 0; elementIndex < outputVariable.elementCount();
+ elementIndex++)
+ {
+ const int location = baseLocation + elementIndex;
+ ASSERT(mData.mOutputVariables.count(location) == 0);
+ unsigned int element = outputVariable.isArray() ? elementIndex : GL_INVALID_INDEX;
+ mData.mOutputVariables[location] =
+ VariableLocation(outputVariable.name, element, outputVariableIndex);
+ }
+ }
+}
+
+bool Program::flattenUniformsAndCheckCaps(const Caps &caps, InfoLog &infoLog)
+{
+ const gl::Shader *vertexShader = mData.getAttachedVertexShader();
+ VectorAndSamplerCount vsCounts;
+
+ std::vector<LinkedUniform> samplerUniforms;
+
+ for (const sh::Uniform &uniform : vertexShader->getUniforms())
+ {
+ if (uniform.staticUse)
+ {
+ vsCounts += flattenUniform(uniform, uniform.name, &samplerUniforms);
+ }
+ }
+
+ if (vsCounts.vectorCount > caps.maxVertexUniformVectors)
+ {
+ infoLog << "Vertex shader active uniforms exceed MAX_VERTEX_UNIFORM_VECTORS ("
+ << caps.maxVertexUniformVectors << ").";
+ return false;
+ }
+
+ if (vsCounts.samplerCount > caps.maxVertexTextureImageUnits)
+ {
+ infoLog << "Vertex shader sampler count exceeds MAX_VERTEX_TEXTURE_IMAGE_UNITS ("
+ << caps.maxVertexTextureImageUnits << ").";
+ return false;
+ }
+
+ const gl::Shader *fragmentShader = mData.getAttachedFragmentShader();
+ VectorAndSamplerCount fsCounts;
+
+ for (const sh::Uniform &uniform : fragmentShader->getUniforms())
+ {
+ if (uniform.staticUse)
+ {
+ fsCounts += flattenUniform(uniform, uniform.name, &samplerUniforms);
+ }
+ }
+
+ if (fsCounts.vectorCount > caps.maxFragmentUniformVectors)
+ {
+ infoLog << "Fragment shader active uniforms exceed MAX_FRAGMENT_UNIFORM_VECTORS ("
+ << caps.maxFragmentUniformVectors << ").";
+ return false;
+ }
+
+ if (fsCounts.samplerCount > caps.maxTextureImageUnits)
+ {
+ infoLog << "Fragment shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS ("
+ << caps.maxTextureImageUnits << ").";
+ return false;
+ }
+
+ mSamplerUniformRange.start = static_cast<unsigned int>(mData.mUniforms.size());
+ mSamplerUniformRange.end =
+ mSamplerUniformRange.start + static_cast<unsigned int>(samplerUniforms.size());
+
+ mData.mUniforms.insert(mData.mUniforms.end(), samplerUniforms.begin(), samplerUniforms.end());
+
+ return true;
+}
+
+Program::VectorAndSamplerCount Program::flattenUniform(const sh::ShaderVariable &uniform,
+ const std::string &fullName,
+ std::vector<LinkedUniform> *samplerUniforms)
+{
+ VectorAndSamplerCount vectorAndSamplerCount;
+
+ if (uniform.isStruct())
+ {
+ for (unsigned int elementIndex = 0; elementIndex < uniform.elementCount(); elementIndex++)
+ {
+ const std::string &elementString = (uniform.isArray() ? ArrayString(elementIndex) : "");
+
+ for (size_t fieldIndex = 0; fieldIndex < uniform.fields.size(); fieldIndex++)
+ {
+ const sh::ShaderVariable &field = uniform.fields[fieldIndex];
+ const std::string &fieldFullName = (fullName + elementString + "." + field.name);
+
+ vectorAndSamplerCount += flattenUniform(field, fieldFullName, samplerUniforms);
+ }
+ }
+
+ return vectorAndSamplerCount;
+ }
+
+ // Not a struct
+ bool isSampler = IsSamplerType(uniform.type);
+ if (!UniformInList(mData.getUniforms(), fullName) && !UniformInList(*samplerUniforms, fullName))
+ {
+ gl::LinkedUniform linkedUniform(uniform.type, uniform.precision, fullName,
+ uniform.arraySize, -1,
+ sh::BlockMemberInfo::getDefaultBlockInfo());
+ linkedUniform.staticUse = true;
+
+ // Store sampler uniforms separately, so we'll append them to the end of the list.
+ if (isSampler)
+ {
+ samplerUniforms->push_back(linkedUniform);
+ }
+ else
+ {
+ mData.mUniforms.push_back(linkedUniform);
+ }
+ }
+
+ unsigned int elementCount = uniform.elementCount();
+
+ // Samplers aren't "real" uniforms, so they don't count towards register usage.
+ // Likewise, don't count "real" uniforms towards sampler count.
+ vectorAndSamplerCount.vectorCount =
+ (isSampler ? 0 : (VariableRegisterCount(uniform.type) * elementCount));
+ vectorAndSamplerCount.samplerCount = (isSampler ? elementCount : 0);
+
+ return vectorAndSamplerCount;
+}
+
+void Program::gatherInterfaceBlockInfo()
+{
+ std::set<std::string> visitedList;
+
+ const gl::Shader *vertexShader = mData.getAttachedVertexShader();
+
+ ASSERT(mData.mUniformBlocks.empty());
+ for (const sh::InterfaceBlock &vertexBlock : vertexShader->getInterfaceBlocks())
+ {
+ // Only 'packed' blocks are allowed to be considered inacive.
+ if (!vertexBlock.staticUse && vertexBlock.layout == sh::BLOCKLAYOUT_PACKED)
+ continue;
+
+ if (visitedList.count(vertexBlock.name) > 0)
+ continue;
+
+ defineUniformBlock(vertexBlock, GL_VERTEX_SHADER);
+ visitedList.insert(vertexBlock.name);
+ }
+
+ const gl::Shader *fragmentShader = mData.getAttachedFragmentShader();
+
+ for (const sh::InterfaceBlock &fragmentBlock : fragmentShader->getInterfaceBlocks())
+ {
+ // Only 'packed' blocks are allowed to be considered inacive.
+ if (!fragmentBlock.staticUse && fragmentBlock.layout == sh::BLOCKLAYOUT_PACKED)
+ continue;
+
+ if (visitedList.count(fragmentBlock.name) > 0)
+ {
+ for (gl::UniformBlock &block : mData.mUniformBlocks)
+ {
+ if (block.name == fragmentBlock.name)
+ {
+ block.fragmentStaticUse = fragmentBlock.staticUse;
+ }
+ }
+
+ continue;
+ }
+
+ defineUniformBlock(fragmentBlock, GL_FRAGMENT_SHADER);
+ visitedList.insert(fragmentBlock.name);
+ }
+}
+
+template <typename VarT>
+void Program::defineUniformBlockMembers(const std::vector<VarT> &fields,
+ const std::string &prefix,
+ int blockIndex)
+{
+ for (const VarT &field : fields)
+ {
+ const std::string &fullName = (prefix.empty() ? field.name : prefix + "." + field.name);
+
+ if (field.isStruct())
+ {
+ for (unsigned int arrayElement = 0; arrayElement < field.elementCount(); arrayElement++)
+ {
+ const std::string uniformElementName =
+ fullName + (field.isArray() ? ArrayString(arrayElement) : "");
+ defineUniformBlockMembers(field.fields, uniformElementName, blockIndex);
+ }
+ }
+ else
+ {
+ // If getBlockMemberInfo returns false, the uniform is optimized out.
+ sh::BlockMemberInfo memberInfo;
+ if (!mProgram->getUniformBlockMemberInfo(fullName, &memberInfo))
+ {
+ continue;
+ }
+
+ LinkedUniform newUniform(field.type, field.precision, fullName, field.arraySize,
+ blockIndex, memberInfo);
+
+ // Since block uniforms have no location, we don't need to store them in the uniform
+ // locations list.
+ mData.mUniforms.push_back(newUniform);
+ }
+ }
+}
+
+void Program::defineUniformBlock(const sh::InterfaceBlock &interfaceBlock, GLenum shaderType)
+{
+ int blockIndex = static_cast<int>(mData.mUniformBlocks.size());
+ size_t blockSize = 0;
+
+ // Don't define this block at all if it's not active in the implementation.
+ if (!mProgram->getUniformBlockSize(interfaceBlock.name, &blockSize))
+ {
+ return;
+ }
+
+ // Track the first and last uniform index to determine the range of active uniforms in the
+ // block.
+ size_t firstBlockUniformIndex = mData.mUniforms.size();
+ defineUniformBlockMembers(interfaceBlock.fields, interfaceBlock.fieldPrefix(), blockIndex);
+ size_t lastBlockUniformIndex = mData.mUniforms.size();
+
+ std::vector<unsigned int> blockUniformIndexes;
+ for (size_t blockUniformIndex = firstBlockUniformIndex;
+ blockUniformIndex < lastBlockUniformIndex; ++blockUniformIndex)
+ {
+ blockUniformIndexes.push_back(static_cast<unsigned int>(blockUniformIndex));
+ }
+
+ if (interfaceBlock.arraySize > 0)
+ {
+ for (unsigned int arrayElement = 0; arrayElement < interfaceBlock.arraySize; ++arrayElement)
+ {
+ UniformBlock block(interfaceBlock.name, true, arrayElement);
+ block.memberUniformIndexes = blockUniformIndexes;
+
+ if (shaderType == GL_VERTEX_SHADER)
+ {
+ block.vertexStaticUse = interfaceBlock.staticUse;
+ }
+ else
+ {
+ ASSERT(shaderType == GL_FRAGMENT_SHADER);
+ block.fragmentStaticUse = interfaceBlock.staticUse;
+ }
+
+ // TODO(jmadill): Determine if we can ever have an inactive array element block.
+ size_t blockElementSize = 0;
+ if (!mProgram->getUniformBlockSize(block.nameWithArrayIndex(), &blockElementSize))
+ {
+ continue;
+ }
+
+ ASSERT(blockElementSize == blockSize);
+ block.dataSize = static_cast<unsigned int>(blockElementSize);
+ mData.mUniformBlocks.push_back(block);
+ }
+ }
+ else
+ {
+ UniformBlock block(interfaceBlock.name, false, 0);
+ block.memberUniformIndexes = blockUniformIndexes;
+
+ if (shaderType == GL_VERTEX_SHADER)
+ {
+ block.vertexStaticUse = interfaceBlock.staticUse;
+ }
+ else
+ {
+ ASSERT(shaderType == GL_FRAGMENT_SHADER);
+ block.fragmentStaticUse = interfaceBlock.staticUse;
+ }
+
+ block.dataSize = static_cast<unsigned int>(blockSize);
+ mData.mUniformBlocks.push_back(block);
+ }
+}
+
+template <typename T>
+void Program::setUniformInternal(GLint location, GLsizei count, const T *v)
+{
+ const VariableLocation &locationInfo = mData.mUniformLocations[location];
+ LinkedUniform *linkedUniform = &mData.mUniforms[locationInfo.index];
+ uint8_t *destPointer = linkedUniform->getDataPtrToElement(locationInfo.element);
+
+ if (VariableComponentType(linkedUniform->type) == GL_BOOL)
+ {
+ // Do a cast conversion for boolean types. From the spec:
+ // "The uniform is set to FALSE if the input value is 0 or 0.0f, and set to TRUE otherwise."
+ GLint *destAsInt = reinterpret_cast<GLint *>(destPointer);
+ for (GLsizei component = 0; component < count; ++component)
+ {
+ destAsInt[component] = (v[component] != static_cast<T>(0) ? GL_TRUE : GL_FALSE);
+ }
+ }
+ else
+ {
+ // Invalide the validation cache if we modify the sampler data.
+ if (linkedUniform->isSampler() && memcmp(destPointer, v, sizeof(T) * count) != 0)
+ {
+ mCachedValidateSamplersResult.reset();
+ }
+
+ memcpy(destPointer, v, sizeof(T) * count);
+ }
+}
+
+template <size_t cols, size_t rows, typename T>
+void Program::setMatrixUniformInternal(GLint location,
+ GLsizei count,
+ GLboolean transpose,
+ const T *v)
+{
+ if (!transpose)
+ {
+ setUniformInternal(location, count * cols * rows, v);
+ return;
+ }
+
+ // Perform a transposing copy.
+ const VariableLocation &locationInfo = mData.mUniformLocations[location];
+ LinkedUniform *linkedUniform = &mData.mUniforms[locationInfo.index];
+ T *destPtr = reinterpret_cast<T *>(linkedUniform->getDataPtrToElement(locationInfo.element));
+ for (GLsizei element = 0; element < count; ++element)
+ {
+ size_t elementOffset = element * rows * cols;
+
+ for (size_t row = 0; row < rows; ++row)
+ {
+ for (size_t col = 0; col < cols; ++col)
+ {
+ destPtr[col * rows + row + elementOffset] = v[row * cols + col + elementOffset];
+ }
+ }
+ }
+}
+
+template <typename DestT>
+void Program::getUniformInternal(GLint location, DestT *dataOut) const
+{
+ const VariableLocation &locationInfo = mData.mUniformLocations[location];
+ const LinkedUniform &uniform = mData.mUniforms[locationInfo.index];
+
+ const uint8_t *srcPointer = uniform.getDataPtrToElement(locationInfo.element);
+
+ GLenum componentType = VariableComponentType(uniform.type);
+ if (componentType == GLTypeToGLenum<DestT>::value)
+ {
+ memcpy(dataOut, srcPointer, uniform.getElementSize());
+ return;
+ }
+
+ int components = VariableComponentCount(uniform.type);
+
+ switch (componentType)
+ {
+ case GL_INT:
+ UniformStateQueryCastLoop<GLint>(dataOut, srcPointer, components);
+ break;
+ case GL_UNSIGNED_INT:
+ UniformStateQueryCastLoop<GLuint>(dataOut, srcPointer, components);
+ break;
+ case GL_BOOL:
+ UniformStateQueryCastLoop<GLboolean>(dataOut, srcPointer, components);
+ break;
+ case GL_FLOAT:
+ UniformStateQueryCastLoop<GLfloat>(dataOut, srcPointer, components);
+ break;
+ default:
+ UNREACHABLE();
+ }
+}
}
diff --git a/src/3rdparty/angle/src/libANGLE/Program.h b/src/3rdparty/angle/src/libANGLE/Program.h
index 38fc83d29d..f885ad1694 100644
--- a/src/3rdparty/angle/src/libANGLE/Program.h
+++ b/src/3rdparty/angle/src/libANGLE/Program.h
@@ -10,26 +10,29 @@
#ifndef LIBANGLE_PROGRAM_H_
#define LIBANGLE_PROGRAM_H_
-#include "libANGLE/angletypes.h"
-#include "libANGLE/Constants.h"
-#include "libANGLE/Error.h"
-#include "libANGLE/RefCountObject.h"
-
-#include "common/angleutils.h"
-
#include <GLES2/gl2.h>
#include <GLSLANG/ShaderLang.h>
-#include <vector>
-#include <string>
#include <set>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include "common/angleutils.h"
+#include "common/mathutil.h"
+#include "common/Optional.h"
+
+#include "libANGLE/angletypes.h"
+#include "libANGLE/Constants.h"
+#include "libANGLE/Debug.h"
+#include "libANGLE/Error.h"
+#include "libANGLE/RefCountObject.h"
namespace rx
{
-class Renderer;
-class Renderer;
-struct TranslatedAttribute;
+class ImplFactory;
class ProgramImpl;
+struct TranslatedAttribute;
}
namespace gl
@@ -66,14 +69,68 @@ class InfoLog : angle::NonCopyable
InfoLog();
~InfoLog();
- int getLength() const;
- void getLog(GLsizei bufSize, GLsizei *length, char *infoLog);
+ size_t getLength() const;
+ void getLog(GLsizei bufSize, GLsizei *length, char *infoLog) const;
void appendSanitized(const char *message);
- void append(const char *info, ...);
void reset();
+
+ // This helper class ensures we append a newline after writing a line.
+ class StreamHelper : angle::NonCopyable
+ {
+ public:
+ StreamHelper(StreamHelper &&rhs)
+ : mStream(rhs.mStream)
+ {
+ rhs.mStream = nullptr;
+ }
+
+ StreamHelper &operator=(StreamHelper &&rhs)
+ {
+ std::swap(mStream, rhs.mStream);
+ return *this;
+ }
+
+ ~StreamHelper()
+ {
+ // Write newline when destroyed on the stack
+ if (mStream)
+ {
+ (*mStream) << std::endl;
+ }
+ }
+
+ template <typename T>
+ StreamHelper &operator<<(const T &value)
+ {
+ (*mStream) << value;
+ return *this;
+ }
+
+ private:
+ friend class InfoLog;
+
+ StreamHelper(std::stringstream *stream)
+ : mStream(stream)
+ {
+ ASSERT(stream);
+ }
+
+ std::stringstream *mStream;
+ };
+
+ template <typename T>
+ StreamHelper operator<<(const T &value)
+ {
+ StreamHelper helper(&mStream);
+ helper << value;
+ return helper;
+ }
+
+ std::string str() const { return mStream.str(); }
+
private:
- char *mInfoLog;
+ std::stringstream mStream;
};
// Struct used for correlating uniforms/elements of uniform arrays to handles
@@ -87,32 +144,94 @@ struct VariableLocation
unsigned int index;
};
-struct LinkedVarying
-{
- LinkedVarying();
- LinkedVarying(const std::string &name, GLenum type, GLsizei size, const std::string &semanticName,
- unsigned int semanticIndex, unsigned int semanticIndexCount);
-
- // Original GL name
- std::string name;
-
- GLenum type;
- GLsizei size;
-
- // DirectX semantic information
- std::string semanticName;
- unsigned int semanticIndex;
- unsigned int semanticIndexCount;
-};
-
-class Program : angle::NonCopyable
+class Program final : angle::NonCopyable, public LabeledObject
{
public:
- Program(rx::ProgramImpl *impl, ResourceManager *manager, GLuint handle);
+ class Data final : angle::NonCopyable
+ {
+ public:
+ Data();
+ ~Data();
+
+ const std::string &getLabel();
+
+ const Shader *getAttachedVertexShader() const { return mAttachedVertexShader; }
+ const Shader *getAttachedFragmentShader() const { return mAttachedFragmentShader; }
+ const std::vector<std::string> &getTransformFeedbackVaryingNames() const
+ {
+ return mTransformFeedbackVaryingNames;
+ }
+ GLint getTransformFeedbackBufferMode() const { return mTransformFeedbackBufferMode; }
+ GLuint getUniformBlockBinding(GLuint uniformBlockIndex) const
+ {
+ ASSERT(uniformBlockIndex < IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS);
+ return mUniformBlockBindings[uniformBlockIndex];
+ }
+ const UniformBlockBindingMask &getActiveUniformBlockBindingsMask() const
+ {
+ return mActiveUniformBlockBindings;
+ }
+ const std::vector<sh::Attribute> &getAttributes() const { return mAttributes; }
+ const AttributesMask &getActiveAttribLocationsMask() const
+ {
+ return mActiveAttribLocationsMask;
+ }
+ const std::map<int, VariableLocation> &getOutputVariables() const
+ {
+ return mOutputVariables;
+ }
+ const std::vector<LinkedUniform> &getUniforms() const { return mUniforms; }
+ const std::vector<VariableLocation> &getUniformLocations() const
+ {
+ return mUniformLocations;
+ }
+ const std::vector<UniformBlock> &getUniformBlocks() const { return mUniformBlocks; }
+
+ const LinkedUniform *getUniformByName(const std::string &name) const;
+ GLint getUniformLocation(const std::string &name) const;
+ GLuint getUniformIndex(const std::string &name) const;
+
+ private:
+ friend class Program;
+
+ std::string mLabel;
+
+ Shader *mAttachedFragmentShader;
+ Shader *mAttachedVertexShader;
+
+ std::vector<std::string> mTransformFeedbackVaryingNames;
+ std::vector<sh::Varying> mTransformFeedbackVaryingVars;
+ GLenum mTransformFeedbackBufferMode;
+
+ GLuint mUniformBlockBindings[IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS];
+ UniformBlockBindingMask mActiveUniformBlockBindings;
+
+ std::vector<sh::Attribute> mAttributes;
+ std::bitset<MAX_VERTEX_ATTRIBS> mActiveAttribLocationsMask;
+
+ // Uniforms are sorted in order:
+ // 1. Non-sampler uniforms
+ // 2. Sampler uniforms
+ // 3. Uniform block uniforms
+ // This makes sampler validation easier, since we don't need a separate list.
+ std::vector<LinkedUniform> mUniforms;
+ std::vector<VariableLocation> mUniformLocations;
+ std::vector<UniformBlock> mUniformBlocks;
+
+ // TODO(jmadill): use unordered/hash map when available
+ std::map<int, VariableLocation> mOutputVariables;
+
+ bool mBinaryRetrieveableHint;
+ };
+
+ Program(rx::ImplFactory *factory, ResourceManager *manager, GLuint handle);
~Program();
GLuint id() const { return mHandle; }
+ void setLabel(const std::string &label) override;
+ const std::string &getLabel() const override;
+
rx::ProgramImpl *getImplementation() { return mProgram; }
const rx::ProgramImpl *getImplementation() const { return mProgram; }
@@ -122,41 +241,43 @@ class Program : angle::NonCopyable
void bindAttributeLocation(GLuint index, const char *name);
- Error link(const Data &data);
- bool isLinked();
+ Error link(const gl::Data &data);
+ bool isLinked() const;
Error loadBinary(GLenum binaryFormat, const void *binary, GLsizei length);
Error saveBinary(GLenum *binaryFormat, void *binary, GLsizei bufSize, GLsizei *length) const;
GLint getBinaryLength() const;
+ void setBinaryRetrievableHint(bool retrievable);
+ bool getBinaryRetrievableHint() const;
int getInfoLogLength() const;
- void getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog);
- void getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders);
+ void getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog) const;
+ void getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders) const;
- GLuint getAttributeLocation(const std::string &name);
- int getSemanticIndex(int attributeIndex);
+ GLuint getAttributeLocation(const std::string &name) const;
+ bool isAttribLocationActive(size_t attribLocation) const;
void getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name);
- GLint getActiveAttributeCount();
- GLint getActiveAttributeMaxLength();
-
- GLint getSamplerMapping(SamplerType type, unsigned int samplerIndex, const Caps &caps);
- GLenum getSamplerTextureType(SamplerType type, unsigned int samplerIndex);
- GLint getUsedSamplerRange(SamplerType type);
- bool usesPointSize() const;
+ GLint getActiveAttributeCount() const;
+ GLint getActiveAttributeMaxLength() const;
+ const std::vector<sh::Attribute> &getAttributes() const { return mData.mAttributes; }
GLint getFragDataLocation(const std::string &name) const;
- void getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name);
- GLint getActiveUniformCount();
- GLint getActiveUniformMaxLength();
+ void getActiveUniform(GLuint index,
+ GLsizei bufsize,
+ GLsizei *length,
+ GLint *size,
+ GLenum *type,
+ GLchar *name) const;
+ GLint getActiveUniformCount() const;
+ GLint getActiveUniformMaxLength() const;
GLint getActiveUniformi(GLuint index, GLenum pname) const;
bool isValidUniformLocation(GLint location) const;
- LinkedUniform *getUniformByLocation(GLint location) const;
- LinkedUniform *getUniformByName(const std::string &name) const;
+ const LinkedUniform &getUniformByLocation(GLint location) const;
- GLint getUniformLocation(const std::string &name);
- GLuint getUniformIndex(const std::string &name);
+ GLint getUniformLocation(const std::string &name) const;
+ GLuint getUniformIndex(const std::string &name) const;
void setUniform1fv(GLint location, GLsizei count, const GLfloat *v);
void setUniform2fv(GLint location, GLsizei count, const GLfloat *v);
void setUniform3fv(GLint location, GLsizei count, const GLfloat *v);
@@ -179,24 +300,21 @@ class Program : angle::NonCopyable
void setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
void setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
- void getUniformfv(GLint location, GLfloat *params);
- void getUniformiv(GLint location, GLint *params);
- void getUniformuiv(GLint location, GLuint *params);
-
- Error applyUniforms();
- Error applyUniformBuffers(const gl::Data &data);
+ void getUniformfv(GLint location, GLfloat *params) const;
+ void getUniformiv(GLint location, GLint *params) const;
+ void getUniformuiv(GLint location, GLuint *params) const;
void getActiveUniformBlockName(GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) const;
void getActiveUniformBlockiv(GLuint uniformBlockIndex, GLenum pname, GLint *params) const;
- GLuint getActiveUniformBlockCount();
- GLint getActiveUniformBlockMaxLength();
+ GLuint getActiveUniformBlockCount() const;
+ GLint getActiveUniformBlockMaxLength() const;
- GLuint getUniformBlockIndex(const std::string &name);
+ GLuint getUniformBlockIndex(const std::string &name) const;
void bindUniformBlock(GLuint uniformBlockIndex, GLuint uniformBlockBinding);
GLuint getUniformBlockBinding(GLuint uniformBlockIndex) const;
- const UniformBlock *getUniformBlockByIndex(GLuint index) const;
+ const UniformBlock &getUniformBlockByIndex(GLuint index) const;
void setTransformFeedbackVaryings(GLsizei count, const GLchar *const *varyings, GLenum bufferMode);
void getTransformFeedbackVarying(GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name) const;
@@ -204,7 +322,6 @@ class Program : angle::NonCopyable
GLsizei getTransformFeedbackVaryingMaxLength() const;
GLenum getTransformFeedbackBufferMode() const;
- static bool linkVaryings(InfoLog &infoLog, Shader *fragmentShader, Shader *vertexShader);
static bool linkValidateUniforms(InfoLog &infoLog, const std::string &uniformName, const sh::Uniform &vertexUniform, const sh::Uniform &fragmentUniform);
static bool linkValidateInterfaceBlockFields(InfoLog &infoLog, const std::string &uniformName, const sh::InterfaceBlockField &vertexUniform, const sh::InterfaceBlockField &fragmentUniform);
@@ -217,14 +334,26 @@ class Program : angle::NonCopyable
void validate(const Caps &caps);
bool validateSamplers(InfoLog *infoLog, const Caps &caps);
bool isValidated() const;
- void updateSamplerMapping();
+
+ const AttributesMask &getActiveAttribLocationsMask() const
+ {
+ return mData.mActiveAttribLocationsMask;
+ }
private:
void unlink(bool destroy = false);
void resetUniformBlockBindings();
- bool linkAttributes(InfoLog &infoLog, const AttributeBindings &attributeBindings, const Shader *vertexShader);
- bool linkUniformBlocks(InfoLog &infoLog, const Shader &vertexShader, const Shader &fragmentShader, const Caps &caps);
+ bool linkAttributes(const gl::Data &data,
+ InfoLog &infoLog,
+ const AttributeBindings &attributeBindings,
+ const Shader *vertexShader);
+ bool linkUniformBlocks(InfoLog &infoLog, const Caps &caps);
+ static bool linkVaryings(InfoLog &infoLog,
+ const Shader *vertexShader,
+ const Shader *fragmentShader);
+ bool linkUniforms(gl::InfoLog &infoLog, const gl::Caps &caps);
+ void indexUniforms();
bool areMatchingInterfaceBlocks(gl::InfoLog &infoLog, const sh::InterfaceBlock &vertexInterfaceBlock,
const sh::InterfaceBlock &fragmentInterfaceBlock);
@@ -235,31 +364,63 @@ class Program : angle::NonCopyable
bool validatePrecision);
static bool linkValidateVaryings(InfoLog &infoLog, const std::string &varyingName, const sh::Varying &vertexVarying, const sh::Varying &fragmentVarying);
- bool gatherTransformFeedbackLinkedVaryings(InfoLog &infoLog, const std::vector<LinkedVarying> &linkedVaryings,
- const std::vector<std::string> &transformFeedbackVaryingNames,
- GLenum transformFeedbackBufferMode,
- std::vector<LinkedVarying> *outTransformFeedbackLinkedVaryings,
- const Caps &caps) const;
+ bool linkValidateTransformFeedback(InfoLog &infoLog,
+ const std::vector<const sh::Varying *> &linkedVaryings,
+ const Caps &caps) const;
+
+ void gatherTransformFeedbackVaryings(const std::vector<const sh::Varying *> &varyings);
bool assignUniformBlockRegister(InfoLog &infoLog, UniformBlock *uniformBlock, GLenum shader, unsigned int registerIndex, const Caps &caps);
void defineOutputVariables(Shader *fragmentShader);
- rx::ProgramImpl *mProgram;
+ std::vector<const sh::Varying *> getMergedVaryings() const;
+ void linkOutputVariables();
- sh::Attribute mLinkedAttribute[MAX_VERTEX_ATTRIBS];
+ bool flattenUniformsAndCheckCaps(const Caps &caps, InfoLog &infoLog);
- std::map<int, VariableLocation> mOutputVariables;
+ struct VectorAndSamplerCount
+ {
+ VectorAndSamplerCount() : vectorCount(0), samplerCount(0) {}
+ VectorAndSamplerCount(const VectorAndSamplerCount &other) = default;
+ VectorAndSamplerCount &operator=(const VectorAndSamplerCount &other) = default;
- bool mValidated;
+ VectorAndSamplerCount &operator+=(const VectorAndSamplerCount &other)
+ {
+ vectorCount += other.vectorCount;
+ samplerCount += other.samplerCount;
+ return *this;
+ }
- Shader *mFragmentShader;
- Shader *mVertexShader;
+ unsigned int vectorCount;
+ unsigned int samplerCount;
+ };
- AttributeBindings mAttributeBindings;
+ VectorAndSamplerCount flattenUniform(const sh::ShaderVariable &uniform,
+ const std::string &fullName,
+ std::vector<LinkedUniform> *samplerUniforms);
+
+ void gatherInterfaceBlockInfo();
+ template <typename VarT>
+ void defineUniformBlockMembers(const std::vector<VarT> &fields,
+ const std::string &prefix,
+ int blockIndex);
+
+ void defineUniformBlock(const sh::InterfaceBlock &interfaceBlock, GLenum shaderType);
- GLuint mUniformBlockBindings[IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS];
+ template <typename T>
+ void setUniformInternal(GLint location, GLsizei count, const T *v);
- std::vector<std::string> mTransformFeedbackVaryings;
- GLenum mTransformFeedbackBufferMode;
+ template <size_t cols, size_t rows, typename T>
+ void setMatrixUniformInternal(GLint location, GLsizei count, GLboolean transpose, const T *v);
+
+ template <typename DestT>
+ void getUniformInternal(GLint location, DestT *dataOut) const;
+
+ Data mData;
+ rx::ProgramImpl *mProgram;
+
+ bool mValidated;
+
+ AttributeBindings mAttributeBindings;
bool mLinked;
bool mDeleteStatus; // Flag to indicate that the program can be deleted when no longer in use
@@ -270,6 +431,11 @@ class Program : angle::NonCopyable
const GLuint mHandle;
InfoLog mInfoLog;
+
+ // Cache for sampler validation
+ Optional<bool> mCachedValidateSamplersResult;
+ std::vector<GLenum> mTextureUnitTypesCache;
+ RangeUI mSamplerUniformRange;
};
}
diff --git a/src/3rdparty/angle/src/libANGLE/Query.cpp b/src/3rdparty/angle/src/libANGLE/Query.cpp
index a402b732bf..cd1fb5f4bc 100644
--- a/src/3rdparty/angle/src/libANGLE/Query.cpp
+++ b/src/3rdparty/angle/src/libANGLE/Query.cpp
@@ -11,9 +11,7 @@
namespace gl
{
-Query::Query(rx::QueryImpl *impl, GLuint id)
- : RefCountObject(id),
- mQuery(impl)
+Query::Query(rx::QueryImpl *impl, GLuint id) : RefCountObject(id), mQuery(impl), mLabel()
{
}
@@ -22,6 +20,16 @@ Query::~Query()
SafeDelete(mQuery);
}
+void Query::setLabel(const std::string &label)
+{
+ mLabel = label;
+}
+
+const std::string &Query::getLabel() const
+{
+ return mLabel;
+}
+
Error Query::begin()
{
return mQuery->begin();
@@ -32,12 +40,32 @@ Error Query::end()
return mQuery->end();
}
+Error Query::queryCounter()
+{
+ return mQuery->queryCounter();
+}
+
+Error Query::getResult(GLint *params)
+{
+ return mQuery->getResult(params);
+}
+
Error Query::getResult(GLuint *params)
{
return mQuery->getResult(params);
}
-Error Query::isResultAvailable(GLuint *available)
+Error Query::getResult(GLint64 *params)
+{
+ return mQuery->getResult(params);
+}
+
+Error Query::getResult(GLuint64 *params)
+{
+ return mQuery->getResult(params);
+}
+
+Error Query::isResultAvailable(bool *available)
{
return mQuery->isResultAvailable(available);
}
@@ -47,4 +75,13 @@ GLenum Query::getType() const
return mQuery->getType();
}
+rx::QueryImpl *Query::getImplementation()
+{
+ return mQuery;
+}
+
+const rx::QueryImpl *Query::getImplementation() const
+{
+ return mQuery;
+}
}
diff --git a/src/3rdparty/angle/src/libANGLE/Query.h b/src/3rdparty/angle/src/libANGLE/Query.h
index 8585fde0e2..5486f983e7 100644
--- a/src/3rdparty/angle/src/libANGLE/Query.h
+++ b/src/3rdparty/angle/src/libANGLE/Query.h
@@ -9,6 +9,7 @@
#ifndef LIBANGLE_QUERY_H_
#define LIBANGLE_QUERY_H_
+#include "libANGLE/Debug.h"
#include "libANGLE/Error.h"
#include "libANGLE/RefCountObject.h"
@@ -24,22 +25,33 @@ class QueryImpl;
namespace gl
{
-class Query : public RefCountObject
+class Query final : public RefCountObject, public LabeledObject
{
public:
Query(rx::QueryImpl *impl, GLuint id);
virtual ~Query();
+ void setLabel(const std::string &label) override;
+ const std::string &getLabel() const override;
+
Error begin();
Error end();
-
+ Error queryCounter();
+ Error getResult(GLint *params);
Error getResult(GLuint *params);
- Error isResultAvailable(GLuint *available);
+ Error getResult(GLint64 *params);
+ Error getResult(GLuint64 *params);
+ Error isResultAvailable(bool *available);
GLenum getType() const;
+ rx::QueryImpl *getImplementation();
+ const rx::QueryImpl *getImplementation() const;
+
private:
rx::QueryImpl *mQuery;
+
+ std::string mLabel;
};
}
diff --git a/src/3rdparty/angle/src/libANGLE/RefCountObject.h b/src/3rdparty/angle/src/libANGLE/RefCountObject.h
index 48c0338c3f..86e6d788b5 100644
--- a/src/3rdparty/angle/src/libANGLE/RefCountObject.h
+++ b/src/3rdparty/angle/src/libANGLE/RefCountObject.h
@@ -21,14 +21,27 @@
class RefCountObject : angle::NonCopyable
{
public:
- explicit RefCountObject(GLuint id);
- virtual ~RefCountObject();
+ explicit RefCountObject(GLuint id) : mId(id), mRefCount(0) {}
- virtual void addRef() const;
- virtual void release() const;
+ void addRef() const { ++mRefCount; }
+
+ void release() const
+ {
+ ASSERT(mRefCount > 0);
+
+ if (--mRefCount == 0)
+ {
+ delete this;
+ }
+ }
GLuint id() const { return mId; }
+ size_t getRefCount() const { return mRefCount; }
+
+ protected:
+ virtual ~RefCountObject() { ASSERT(mRefCount == 0); }
+
private:
GLuint mId;
@@ -38,7 +51,7 @@ class RefCountObject : angle::NonCopyable
template <class ObjectType>
class BindingPointer
{
-public:
+ public:
BindingPointer()
: mObject(nullptr)
{
@@ -73,7 +86,13 @@ public:
ObjectType *operator->() const { return mObject; }
GLuint id() const { return (mObject != nullptr) ? mObject->id() : 0; }
- bool operator!() const { return (mObject == nullptr); }
+
+ bool operator==(const BindingPointer<ObjectType> &other) const
+ {
+ return mObject == other.mObject;
+ }
+
+ bool operator!=(const BindingPointer<ObjectType> &other) const { return !(*this == other); }
private:
ObjectType *mObject;
@@ -102,6 +121,16 @@ class OffsetBindingPointer : public BindingPointer<ObjectType>
GLintptr getOffset() const { return mOffset; }
GLsizeiptr getSize() const { return mSize; }
+ bool operator==(const OffsetBindingPointer<ObjectType> &other) const
+ {
+ return this->get() == other.get() && mOffset == other.mOffset && mSize == other.mSize;
+ }
+
+ bool operator!=(const OffsetBindingPointer<ObjectType> &other) const
+ {
+ return !(*this == other);
+ }
+
private:
GLintptr mOffset;
GLsizeiptr mSize;
diff --git a/src/3rdparty/angle/src/libANGLE/Renderbuffer.cpp b/src/3rdparty/angle/src/libANGLE/Renderbuffer.cpp
index 6a0cde812b..161fbea797 100644
--- a/src/3rdparty/angle/src/libANGLE/Renderbuffer.cpp
+++ b/src/3rdparty/angle/src/libANGLE/Renderbuffer.cpp
@@ -12,20 +12,21 @@
#include "common/utilities.h"
#include "libANGLE/FramebufferAttachment.h"
+#include "libANGLE/Image.h"
#include "libANGLE/Texture.h"
#include "libANGLE/formatutils.h"
#include "libANGLE/renderer/d3d/RenderTargetD3D.h"
-#include "libANGLE/renderer/RenderbufferImpl.h"
namespace gl
{
Renderbuffer::Renderbuffer(rx::RenderbufferImpl *impl, GLuint id)
- : RefCountObject(id),
- mRenderbuffer(impl),
- mWidth(0),
- mHeight(0),
- mInternalFormat(GL_RGBA4),
- mSamples(0)
+ : egl::ImageSibling(id),
+ mRenderbuffer(impl),
+ mLabel(),
+ mWidth(0),
+ mHeight(0),
+ mInternalFormat(GL_RGBA4),
+ mSamples(0)
{
}
@@ -34,16 +35,28 @@ Renderbuffer::~Renderbuffer()
SafeDelete(mRenderbuffer);
}
+void Renderbuffer::setLabel(const std::string &label)
+{
+ mLabel = label;
+}
+
+const std::string &Renderbuffer::getLabel() const
+{
+ return mLabel;
+}
+
Error Renderbuffer::setStorage(GLenum internalformat, size_t width, size_t height)
{
+ orphanImages();
+
Error error = mRenderbuffer->setStorage(internalformat, width, height);
if (error.isError())
{
return error;
}
- mWidth = width;
- mHeight = height;
+ mWidth = static_cast<GLsizei>(width);
+ mHeight = static_cast<GLsizei>(height);
mInternalFormat = internalformat;
mSamples = 0;
@@ -52,16 +65,38 @@ Error Renderbuffer::setStorage(GLenum internalformat, size_t width, size_t heigh
Error Renderbuffer::setStorageMultisample(size_t samples, GLenum internalformat, size_t width, size_t height)
{
+ orphanImages();
+
Error error = mRenderbuffer->setStorageMultisample(samples, internalformat, width, height);
if (error.isError())
{
return error;
}
- mWidth = width;
- mHeight = height;
+ mWidth = static_cast<GLsizei>(width);
+ mHeight = static_cast<GLsizei>(height);
mInternalFormat = internalformat;
- mSamples = samples;
+ mSamples = static_cast<GLsizei>(samples);
+
+ return Error(GL_NO_ERROR);
+}
+
+Error Renderbuffer::setStorageEGLImageTarget(egl::Image *image)
+{
+ orphanImages();
+
+ Error error = mRenderbuffer->setStorageEGLImageTarget(image);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ setTargetImage(image);
+
+ mWidth = static_cast<GLsizei>(image->getWidth());
+ mHeight = static_cast<GLsizei>(image->getHeight());
+ mInternalFormat = image->getInternalFormat();
+ mSamples = 0;
return Error(GL_NO_ERROR);
}
@@ -127,4 +162,23 @@ GLuint Renderbuffer::getStencilSize() const
return GetInternalFormatInfo(mInternalFormat).stencilBits;
}
+void Renderbuffer::onAttach()
+{
+ addRef();
+}
+
+void Renderbuffer::onDetach()
+{
+ release();
+}
+
+GLuint Renderbuffer::getId() const
+{
+ return id();
+}
+
+Extents Renderbuffer::getAttachmentSize(const FramebufferAttachment::Target & /*target*/) const
+{
+ return Extents(mWidth, mHeight, 1);
+}
}
diff --git a/src/3rdparty/angle/src/libANGLE/Renderbuffer.h b/src/3rdparty/angle/src/libANGLE/Renderbuffer.h
index 98c7eb0f10..04af03e879 100644
--- a/src/3rdparty/angle/src/libANGLE/Renderbuffer.h
+++ b/src/3rdparty/angle/src/libANGLE/Renderbuffer.h
@@ -12,34 +12,34 @@
#define LIBANGLE_RENDERBUFFER_H_
#include "angle_gl.h"
-
-#include "libANGLE/Error.h"
-#include "libANGLE/RefCountObject.h"
-
#include "common/angleutils.h"
-
-namespace rx
-{
-class RenderbufferImpl;
-}
+#include "libANGLE/Debug.h"
+#include "libANGLE/Error.h"
+#include "libANGLE/FramebufferAttachment.h"
+#include "libANGLE/Image.h"
+#include "libANGLE/renderer/RenderbufferImpl.h"
namespace gl
{
-class FramebufferAttachment;
-
// A GL renderbuffer object is usually used as a depth or stencil buffer attachment
// for a framebuffer object. The renderbuffer itself is a distinct GL object, see
// FramebufferAttachment and Framebuffer for how they are applied to an FBO via an
// attachment point.
-class Renderbuffer : public RefCountObject
+class Renderbuffer final : public egl::ImageSibling,
+ public gl::FramebufferAttachmentObject,
+ public LabeledObject
{
public:
Renderbuffer(rx::RenderbufferImpl *impl, GLuint id);
virtual ~Renderbuffer();
+ void setLabel(const std::string &label) override;
+ const std::string &getLabel() const override;
+
Error setStorage(GLenum internalformat, size_t width, size_t height);
Error setStorageMultisample(size_t samples, GLenum internalformat, size_t width, size_t height);
+ Error setStorageEGLImageTarget(egl::Image *imageTarget);
rx::RenderbufferImpl *getImplementation();
const rx::RenderbufferImpl *getImplementation() const;
@@ -55,9 +55,22 @@ class Renderbuffer : public RefCountObject
GLuint getDepthSize() const;
GLuint getStencilSize() const;
+ // FramebufferAttachmentObject Impl
+ Extents getAttachmentSize(const FramebufferAttachment::Target &target) const override;
+ GLenum getAttachmentInternalFormat(const FramebufferAttachment::Target &/*target*/) const override { return getInternalFormat(); }
+ GLsizei getAttachmentSamples(const FramebufferAttachment::Target &/*target*/) const override { return getSamples(); }
+
+ void onAttach() override;
+ void onDetach() override;
+ GLuint getId() const override;
+
private:
+ rx::FramebufferAttachmentObjectImpl *getAttachmentImpl() const override { return mRenderbuffer; }
+
rx::RenderbufferImpl *mRenderbuffer;
+ std::string mLabel;
+
GLsizei mWidth;
GLsizei mHeight;
GLenum mInternalFormat;
diff --git a/src/3rdparty/angle/src/libANGLE/ResourceManager.cpp b/src/3rdparty/angle/src/libANGLE/ResourceManager.cpp
index aaf144cfa9..dc9dad1e9f 100644
--- a/src/3rdparty/angle/src/libANGLE/ResourceManager.cpp
+++ b/src/3rdparty/angle/src/libANGLE/ResourceManager.cpp
@@ -88,13 +88,13 @@ GLuint ResourceManager::createBuffer()
}
// Returns an unused shader/program name
-GLuint ResourceManager::createShader(const gl::Data &data, GLenum type)
+GLuint ResourceManager::createShader(const gl::Limitations &rendererLimitations, GLenum type)
{
GLuint handle = mProgramShaderHandleAllocator.allocate();
if (type == GL_VERTEX_SHADER || type == GL_FRAGMENT_SHADER)
{
- mShaderMap[handle] = new Shader(this, mFactory->createShader(type), type, handle);
+ mShaderMap[handle] = new Shader(this, mFactory, rendererLimitations, type, handle);
}
else UNREACHABLE();
@@ -106,7 +106,7 @@ GLuint ResourceManager::createProgram()
{
GLuint handle = mProgramShaderHandleAllocator.allocate();
- mProgramMap[handle] = new Program(mFactory->createProgram(), this, handle);
+ mProgramMap[handle] = new Program(mFactory, this, handle);
return handle;
}
@@ -441,7 +441,7 @@ void ResourceManager::checkSamplerAllocation(GLuint sampler)
{
if (sampler != 0 && !getSampler(sampler))
{
- Sampler *samplerObject = new Sampler(sampler);
+ Sampler *samplerObject = new Sampler(mFactory, sampler);
mSamplerMap[sampler] = samplerObject;
samplerObject->addRef();
// Samplers cannot be created via Bind
diff --git a/src/3rdparty/angle/src/libANGLE/ResourceManager.h b/src/3rdparty/angle/src/libANGLE/ResourceManager.h
index 8e95e8840a..2073e9d728 100644
--- a/src/3rdparty/angle/src/libANGLE/ResourceManager.h
+++ b/src/3rdparty/angle/src/libANGLE/ResourceManager.h
@@ -25,13 +25,14 @@ class ImplFactory;
namespace gl
{
class Buffer;
-class Shader;
+struct Data;
+class FenceSync;
+struct Limitations;
class Program;
-class Texture;
class Renderbuffer;
class Sampler;
-class FenceSync;
-struct Data;
+class Shader;
+class Texture;
class ResourceManager : angle::NonCopyable
{
@@ -43,7 +44,7 @@ class ResourceManager : angle::NonCopyable
void release();
GLuint createBuffer();
- GLuint createShader(const gl::Data &data, GLenum type);
+ GLuint createShader(const gl::Limitations &rendererLimitations, GLenum type);
GLuint createProgram();
GLuint createTexture();
GLuint createRenderbuffer();
diff --git a/src/3rdparty/angle/src/libANGLE/Sampler.cpp b/src/3rdparty/angle/src/libANGLE/Sampler.cpp
index d58bd5a862..d8d606a46f 100644
--- a/src/3rdparty/angle/src/libANGLE/Sampler.cpp
+++ b/src/3rdparty/angle/src/libANGLE/Sampler.cpp
@@ -9,35 +9,144 @@
#include "libANGLE/Sampler.h"
#include "libANGLE/angletypes.h"
+#include "libANGLE/renderer/ImplFactory.h"
+#include "libANGLE/renderer/SamplerImpl.h"
namespace gl
{
-Sampler::Sampler(GLuint id)
- : RefCountObject(id),
- mMinFilter(GL_NEAREST_MIPMAP_LINEAR),
- mMagFilter(GL_LINEAR),
- mWrapS(GL_REPEAT),
- mWrapT(GL_REPEAT),
- mWrapR(GL_REPEAT),
- mMinLod(-1000.0f),
- mMaxLod(1000.0f),
- mComparisonMode(GL_NONE),
- mComparisonFunc(GL_LEQUAL)
+Sampler::Sampler(rx::ImplFactory *factory, GLuint id)
+ : RefCountObject(id), mImpl(factory->createSampler()), mLabel(), mSamplerState()
{
}
-void Sampler::getState(SamplerState *samplerState) const
+Sampler::~Sampler()
{
- samplerState->minFilter = mMinFilter;
- samplerState->magFilter = mMagFilter;
- samplerState->wrapS = mWrapS;
- samplerState->wrapT = mWrapT;
- samplerState->wrapR = mWrapR;
- samplerState->minLod = mMinLod;
- samplerState->maxLod = mMaxLod;
- samplerState->compareMode = mComparisonMode;
- samplerState->compareFunc = mComparisonFunc;
+ SafeDelete(mImpl);
}
+void Sampler::setLabel(const std::string &label)
+{
+ mLabel = label;
+}
+
+const std::string &Sampler::getLabel() const
+{
+ return mLabel;
+}
+
+void Sampler::setMinFilter(GLenum minFilter)
+{
+ mSamplerState.minFilter = minFilter;
+}
+
+GLenum Sampler::getMinFilter() const
+{
+ return mSamplerState.minFilter;
+}
+
+void Sampler::setMagFilter(GLenum magFilter)
+{
+ mSamplerState.magFilter = magFilter;
+}
+
+GLenum Sampler::getMagFilter() const
+{
+ return mSamplerState.magFilter;
+}
+
+void Sampler::setWrapS(GLenum wrapS)
+{
+ mSamplerState.wrapS = wrapS;
+}
+
+GLenum Sampler::getWrapS() const
+{
+ return mSamplerState.wrapS;
+}
+
+void Sampler::setWrapT(GLenum wrapT)
+{
+ mSamplerState.wrapT = wrapT;
+}
+
+GLenum Sampler::getWrapT() const
+{
+ return mSamplerState.wrapT;
+}
+
+void Sampler::setWrapR(GLenum wrapR)
+{
+ mSamplerState.wrapR = wrapR;
+}
+
+GLenum Sampler::getWrapR() const
+{
+ return mSamplerState.wrapR;
+}
+
+void Sampler::setMaxAnisotropy(float maxAnisotropy)
+{
+ mSamplerState.maxAnisotropy = maxAnisotropy;
+}
+
+float Sampler::getMaxAnisotropy() const
+{
+ return mSamplerState.maxAnisotropy;
+}
+
+void Sampler::setMinLod(GLfloat minLod)
+{
+ mSamplerState.minLod = minLod;
+}
+
+GLfloat Sampler::getMinLod() const
+{
+ return mSamplerState.minLod;
+}
+
+void Sampler::setMaxLod(GLfloat maxLod)
+{
+ mSamplerState.maxLod = maxLod;
+}
+
+GLfloat Sampler::getMaxLod() const
+{
+ return mSamplerState.maxLod;
+}
+
+void Sampler::setCompareMode(GLenum compareMode)
+{
+ mSamplerState.compareMode = compareMode;
+}
+
+GLenum Sampler::getCompareMode() const
+{
+ return mSamplerState.compareMode;
+}
+
+void Sampler::setCompareFunc(GLenum compareFunc)
+{
+ mSamplerState.compareFunc = compareFunc;
+}
+
+GLenum Sampler::getCompareFunc() const
+{
+ return mSamplerState.compareFunc;
+}
+
+const SamplerState &Sampler::getSamplerState() const
+{
+ return mSamplerState;
+}
+
+const rx::SamplerImpl *Sampler::getImplementation() const
+{
+ return mImpl;
+}
+
+rx::SamplerImpl *Sampler::getImplementation()
+{
+ return mImpl;
+}
}
diff --git a/src/3rdparty/angle/src/libANGLE/Sampler.h b/src/3rdparty/angle/src/libANGLE/Sampler.h
index d33798ff15..a40b1655fc 100644
--- a/src/3rdparty/angle/src/libANGLE/Sampler.h
+++ b/src/3rdparty/angle/src/libANGLE/Sampler.h
@@ -10,49 +10,69 @@
#ifndef LIBANGLE_SAMPLER_H_
#define LIBANGLE_SAMPLER_H_
+#include "libANGLE/angletypes.h"
+#include "libANGLE/Debug.h"
#include "libANGLE/RefCountObject.h"
+namespace rx
+{
+class ImplFactory;
+class SamplerImpl;
+}
+
namespace gl
{
-struct SamplerState;
-class Sampler : public RefCountObject
+class Sampler final : public RefCountObject, public LabeledObject
{
public:
- Sampler(GLuint id);
-
- void setMinFilter(GLenum minFilter) { mMinFilter = minFilter; }
- void setMagFilter(GLenum magFilter) { mMagFilter = magFilter; }
- void setWrapS(GLenum wrapS) { mWrapS = wrapS; }
- void setWrapT(GLenum wrapT) { mWrapT = wrapT; }
- void setWrapR(GLenum wrapR) { mWrapR = wrapR; }
- void setMinLod(GLfloat minLod) { mMinLod = minLod; }
- void setMaxLod(GLfloat maxLod) { mMaxLod = maxLod; }
- void setComparisonMode(GLenum comparisonMode) { mComparisonMode = comparisonMode; }
- void setComparisonFunc(GLenum comparisonFunc) { mComparisonFunc = comparisonFunc; }
-
- GLenum getMinFilter() const { return mMinFilter; }
- GLenum getMagFilter() const { return mMagFilter; }
- GLenum getWrapS() const { return mWrapS; }
- GLenum getWrapT() const { return mWrapT; }
- GLenum getWrapR() const { return mWrapR; }
- GLfloat getMinLod() const { return mMinLod; }
- GLfloat getMaxLod() const { return mMaxLod; }
- GLenum getComparisonMode() const { return mComparisonMode; }
- GLenum getComparisonFunc() const { return mComparisonFunc; }
-
- void getState(SamplerState *samplerState) const;
+ Sampler(rx::ImplFactory *factory, GLuint id);
+ ~Sampler() override;
+
+ void setLabel(const std::string &label) override;
+ const std::string &getLabel() const override;
+
+ void setMinFilter(GLenum minFilter);
+ GLenum getMinFilter() const;
+
+ void setMagFilter(GLenum magFilter);
+ GLenum getMagFilter() const;
+
+ void setWrapS(GLenum wrapS);
+ GLenum getWrapS() const;
+
+ void setWrapT(GLenum wrapT);
+ GLenum getWrapT() const;
+
+ void setWrapR(GLenum wrapR);
+ GLenum getWrapR() const;
+
+ void setMaxAnisotropy(float maxAnisotropy);
+ float getMaxAnisotropy() const;
+
+ void setMinLod(GLfloat minLod);
+ GLfloat getMinLod() const;
+
+ void setMaxLod(GLfloat maxLod);
+ GLfloat getMaxLod() const;
+
+ void setCompareMode(GLenum compareMode);
+ GLenum getCompareMode() const;
+
+ void setCompareFunc(GLenum compareFunc);
+ GLenum getCompareFunc() const;
+
+ const SamplerState &getSamplerState() const;
+
+ const rx::SamplerImpl *getImplementation() const;
+ rx::SamplerImpl *getImplementation();
private:
- GLenum mMinFilter;
- GLenum mMagFilter;
- GLenum mWrapS;
- GLenum mWrapT;
- GLenum mWrapR;
- GLfloat mMinLod;
- GLfloat mMaxLod;
- GLenum mComparisonMode;
- GLenum mComparisonFunc;
+ rx::SamplerImpl *mImpl;
+
+ std::string mLabel;
+
+ SamplerState mSamplerState;
};
}
diff --git a/src/3rdparty/angle/src/libANGLE/Shader.cpp b/src/3rdparty/angle/src/libANGLE/Shader.cpp
index 7af4ff358d..bbe9077fc9 100644
--- a/src/3rdparty/angle/src/libANGLE/Shader.cpp
+++ b/src/3rdparty/angle/src/libANGLE/Shader.cpp
@@ -9,35 +9,108 @@
// functionality. [OpenGL ES 2.0.24] section 2.10 page 24 and section 3.8 page 84.
#include "libANGLE/Shader.h"
+
+#include <sstream>
+
+#include "common/utilities.h"
+#include "GLSLANG/ShaderLang.h"
+#include "libANGLE/Compiler.h"
+#include "libANGLE/Constants.h"
#include "libANGLE/renderer/Renderer.h"
#include "libANGLE/renderer/ShaderImpl.h"
-#include "libANGLE/Constants.h"
#include "libANGLE/ResourceManager.h"
-#include "common/utilities.h"
+namespace gl
+{
-#include "GLSLANG/ShaderLang.h"
+namespace
+{
+template <typename VarT>
+std::vector<VarT> GetActiveShaderVariables(const std::vector<VarT> *variableList)
+{
+ ASSERT(variableList);
+ std::vector<VarT> result;
+ for (size_t varIndex = 0; varIndex < variableList->size(); varIndex++)
+ {
+ const VarT &var = variableList->at(varIndex);
+ if (var.staticUse)
+ {
+ result.push_back(var);
+ }
+ }
+ return result;
+}
-#include <sstream>
+template <typename VarT>
+const std::vector<VarT> &GetShaderVariables(const std::vector<VarT> *variableList)
+{
+ ASSERT(variableList);
+ return *variableList;
+}
-namespace gl
+} // anonymous namespace
+
+// true if varying x has a higher priority in packing than y
+bool CompareShaderVar(const sh::ShaderVariable &x, const sh::ShaderVariable &y)
{
+ if (x.type == y.type)
+ {
+ return x.arraySize > y.arraySize;
+ }
-Shader::Shader(ResourceManager *manager, rx::ShaderImpl *impl, GLenum type, GLuint handle)
- : mShader(impl),
- mType(type),
+ // Special case for handling structs: we sort these to the end of the list
+ if (x.type == GL_STRUCT_ANGLEX)
+ {
+ return false;
+ }
+
+ if (y.type == GL_STRUCT_ANGLEX)
+ {
+ return true;
+ }
+
+ return gl::VariableSortOrder(x.type) < gl::VariableSortOrder(y.type);
+}
+
+Shader::Data::Data(GLenum shaderType) : mLabel(), mShaderType(shaderType), mShaderVersion(100)
+{
+}
+
+Shader::Data::~Data()
+{
+}
+
+Shader::Shader(ResourceManager *manager,
+ rx::ImplFactory *implFactory,
+ const gl::Limitations &rendererLimitations,
+ GLenum type,
+ GLuint handle)
+ : mData(type),
+ mImplementation(implFactory->createShader(mData)),
+ mRendererLimitations(rendererLimitations),
mHandle(handle),
- mResourceManager(manager),
+ mType(type),
mRefCount(0),
mDeleteStatus(false),
- mCompiled(false)
+ mCompiled(false),
+ mResourceManager(manager)
{
- ASSERT(impl);
+ ASSERT(mImplementation);
}
Shader::~Shader()
{
- SafeDelete(mShader);
+ SafeDelete(mImplementation);
+}
+
+void Shader::setLabel(const std::string &label)
+{
+ mData.mLabel = label;
+}
+
+const std::string &Shader::getLabel() const
+{
+ return mData.mLabel;
}
GLuint Shader::getHandle() const
@@ -61,12 +134,17 @@ void Shader::setSource(GLsizei count, const char *const *string, const GLint *le
}
}
- mSource = stream.str();
+ mData.mSource = stream.str();
}
int Shader::getInfoLogLength() const
{
- return mShader->getInfoLog().empty() ? 0 : (mShader->getInfoLog().length() + 1);
+ if (mInfoLog.empty())
+ {
+ return 0;
+ }
+
+ return (static_cast<int>(mInfoLog.length()) + 1);
}
void Shader::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog) const
@@ -75,8 +153,8 @@ void Shader::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog) const
if (bufSize > 0)
{
- index = std::min(bufSize - 1, static_cast<GLsizei>(mShader->getInfoLog().length()));
- memcpy(infoLog, mShader->getInfoLog().c_str(), index);
+ index = std::min(bufSize - 1, static_cast<GLsizei>(mInfoLog.length()));
+ memcpy(infoLog, mInfoLog.c_str(), index);
infoLog[index] = '\0';
}
@@ -89,12 +167,28 @@ void Shader::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog) const
int Shader::getSourceLength() const
{
- return mSource.empty() ? 0 : (mSource.length() + 1);
+ return mData.mSource.empty() ? 0 : (static_cast<int>(mData.mSource.length()) + 1);
}
int Shader::getTranslatedSourceLength() const
{
- return mShader->getTranslatedSource().empty() ? 0 : (mShader->getTranslatedSource().length() + 1);
+ if (mData.mTranslatedSource.empty())
+ {
+ return 0;
+ }
+
+ return (static_cast<int>(mData.mTranslatedSource.length()) + 1);
+}
+
+int Shader::getTranslatedSourceWithDebugInfoLength() const
+{
+ const std::string &debugInfo = mImplementation->getDebugInfo();
+ if (debugInfo.empty())
+ {
+ return 0;
+ }
+
+ return (static_cast<int>(debugInfo.length()) + 1);
}
void Shader::getSourceImpl(const std::string &source, GLsizei bufSize, GLsizei *length, char *buffer)
@@ -117,23 +211,117 @@ void Shader::getSourceImpl(const std::string &source, GLsizei bufSize, GLsizei *
void Shader::getSource(GLsizei bufSize, GLsizei *length, char *buffer) const
{
- getSourceImpl(mSource, bufSize, length, buffer);
+ getSourceImpl(mData.mSource, bufSize, length, buffer);
}
void Shader::getTranslatedSource(GLsizei bufSize, GLsizei *length, char *buffer) const
{
- getSourceImpl(mShader->getTranslatedSource(), bufSize, length, buffer);
+ getSourceImpl(mData.mTranslatedSource, bufSize, length, buffer);
}
void Shader::getTranslatedSourceWithDebugInfo(GLsizei bufSize, GLsizei *length, char *buffer) const
{
- std::string debugInfo(mShader->getDebugInfo());
+ const std::string &debugInfo = mImplementation->getDebugInfo();
getSourceImpl(debugInfo, bufSize, length, buffer);
}
void Shader::compile(Compiler *compiler)
{
- mCompiled = mShader->compile(compiler, mSource);
+ mData.mTranslatedSource.clear();
+ mInfoLog.clear();
+ mData.mShaderVersion = 100;
+ mData.mVaryings.clear();
+ mData.mUniforms.clear();
+ mData.mInterfaceBlocks.clear();
+ mData.mActiveAttributes.clear();
+ mData.mActiveOutputVariables.clear();
+
+ ShHandle compilerHandle = compiler->getCompilerHandle(mData.mShaderType);
+
+ std::stringstream sourceStream;
+
+ std::string sourcePath;
+ int additionalOptions =
+ mImplementation->prepareSourceAndReturnOptions(&sourceStream, &sourcePath);
+ int compileOptions = (SH_OBJECT_CODE | SH_VARIABLES | additionalOptions);
+
+ // Some targets (eg D3D11 Feature Level 9_3 and below) do not support non-constant loop indexes
+ // in fragment shaders. Shader compilation will fail. To provide a better error message we can
+ // instruct the compiler to pre-validate.
+ if (mRendererLimitations.shadersRequireIndexedLoopValidation)
+ {
+ compileOptions |= SH_VALIDATE_LOOP_INDEXING;
+ }
+
+ std::string sourceString = sourceStream.str();
+ std::vector<const char *> sourceCStrings;
+
+ if (!sourcePath.empty())
+ {
+ sourceCStrings.push_back(sourcePath.c_str());
+ }
+
+ sourceCStrings.push_back(sourceString.c_str());
+
+ bool result =
+ ShCompile(compilerHandle, &sourceCStrings[0], sourceCStrings.size(), compileOptions);
+
+ if (!result)
+ {
+ mInfoLog = ShGetInfoLog(compilerHandle);
+ TRACE("\n%s", mInfoLog.c_str());
+ mCompiled = false;
+ return;
+ }
+
+ mData.mTranslatedSource = ShGetObjectCode(compilerHandle);
+
+#ifndef NDEBUG
+ // Prefix translated shader with commented out un-translated shader.
+ // Useful in diagnostics tools which capture the shader source.
+ std::ostringstream shaderStream;
+ shaderStream << "// GLSL\n";
+ shaderStream << "//\n";
+
+ size_t curPos = 0;
+ while (curPos != std::string::npos)
+ {
+ size_t nextLine = mData.mSource.find("\n", curPos);
+ size_t len = (nextLine == std::string::npos) ? std::string::npos : (nextLine - curPos + 1);
+
+ shaderStream << "// " << mData.mSource.substr(curPos, len);
+
+ curPos = (nextLine == std::string::npos) ? std::string::npos : (nextLine + 1);
+ }
+ shaderStream << "\n\n";
+ shaderStream << mData.mTranslatedSource;
+ mData.mTranslatedSource = shaderStream.str();
+#endif
+
+ // Gather the shader information
+ mData.mShaderVersion = ShGetShaderVersion(compilerHandle);
+
+ mData.mVaryings = GetShaderVariables(ShGetVaryings(compilerHandle));
+ mData.mUniforms = GetShaderVariables(ShGetUniforms(compilerHandle));
+ mData.mInterfaceBlocks = GetShaderVariables(ShGetInterfaceBlocks(compilerHandle));
+
+ if (mData.mShaderType == GL_VERTEX_SHADER)
+ {
+ mData.mActiveAttributes = GetActiveShaderVariables(ShGetAttributes(compilerHandle));
+ }
+ else
+ {
+ ASSERT(mData.mShaderType == GL_FRAGMENT_SHADER);
+
+ // TODO(jmadill): Figure out why we only sort in the FS, and if we need to.
+ std::sort(mData.mVaryings.begin(), mData.mVaryings.end(), CompareShaderVar);
+ mData.mActiveOutputVariables =
+ GetActiveShaderVariables(ShGetOutputVariables(compilerHandle));
+ }
+
+ ASSERT(!mData.mTranslatedSource.empty());
+
+ mCompiled = mImplementation->postTranslateCompile(compiler, &mInfoLog);
}
void Shader::addRef()
@@ -166,62 +354,41 @@ void Shader::flagForDeletion()
mDeleteStatus = true;
}
-const std::vector<gl::PackedVarying> &Shader::getVaryings() const
-{
- return mShader->getVaryings();
-}
-
-const std::vector<sh::Uniform> &Shader::getUniforms() const
-{
- return mShader->getUniforms();
-}
-
-const std::vector<sh::InterfaceBlock> &Shader::getInterfaceBlocks() const
+int Shader::getShaderVersion() const
{
- return mShader->getInterfaceBlocks();
+ return mData.mShaderVersion;
}
-const std::vector<sh::Attribute> &Shader::getActiveAttributes() const
+const std::vector<sh::Varying> &Shader::getVaryings() const
{
- return mShader->getActiveAttributes();
+ return mData.getVaryings();
}
-const std::vector<sh::Attribute> &Shader::getActiveOutputVariables() const
-{
- return mShader->getActiveOutputVariables();
-}
-
-std::vector<gl::PackedVarying> &Shader::getVaryings()
-{
- return mShader->getVaryings();
-}
-
-std::vector<sh::Uniform> &Shader::getUniforms()
+const std::vector<sh::Uniform> &Shader::getUniforms() const
{
- return mShader->getUniforms();
+ return mData.getUniforms();
}
-std::vector<sh::InterfaceBlock> &Shader::getInterfaceBlocks()
+const std::vector<sh::InterfaceBlock> &Shader::getInterfaceBlocks() const
{
- return mShader->getInterfaceBlocks();
+ return mData.getInterfaceBlocks();
}
-std::vector<sh::Attribute> &Shader::getActiveAttributes()
+const std::vector<sh::Attribute> &Shader::getActiveAttributes() const
{
- return mShader->getActiveAttributes();
+ return mData.getActiveAttributes();
}
-std::vector<sh::Attribute> &Shader::getActiveOutputVariables()
+const std::vector<sh::OutputVariable> &Shader::getActiveOutputVariables() const
{
- return mShader->getActiveOutputVariables();
+ return mData.getActiveOutputVariables();
}
-
int Shader::getSemanticIndex(const std::string &attributeName) const
{
if (!attributeName.empty())
{
- const auto &activeAttributes = mShader->getActiveAttributes();
+ const auto &activeAttributes = mData.getActiveAttributes();
int semanticIndex = 0;
for (size_t attributeIndex = 0; attributeIndex < activeAttributes.size(); attributeIndex++)
diff --git a/src/3rdparty/angle/src/libANGLE/Shader.h b/src/3rdparty/angle/src/libANGLE/Shader.h
index 10e79c7499..997977c87b 100644
--- a/src/3rdparty/angle/src/libANGLE/Shader.h
+++ b/src/3rdparty/angle/src/libANGLE/Shader.h
@@ -21,50 +21,83 @@
#include "common/angleutils.h"
#include "libANGLE/angletypes.h"
+#include "libANGLE/Debug.h"
namespace rx
{
+class ImplFactory;
class ShaderImpl;
+class ShaderSh;
}
namespace gl
{
class Compiler;
+struct Limitations;
class ResourceManager;
struct Data;
-struct PackedVarying : public sh::Varying
-{
- unsigned int registerIndex; // Assigned during link
- unsigned int columnIndex; // Assigned during link, defaults to 0
-
- PackedVarying(const sh::Varying &varying)
- : sh::Varying(varying),
- registerIndex(GL_INVALID_INDEX),
- columnIndex(0)
- {}
-
- bool registerAssigned() const { return registerIndex != GL_INVALID_INDEX; }
- bool isBuiltIn() const { return name.compare(0, 3, "gl_") == 0; }
-
- void resetRegisterAssignment()
- {
- registerIndex = GL_INVALID_INDEX;
- }
-};
-
-class Shader : angle::NonCopyable
+class Shader final : angle::NonCopyable, public LabeledObject
{
public:
- Shader(ResourceManager *manager, rx::ShaderImpl *impl, GLenum type, GLuint handle);
+ class Data final : angle::NonCopyable
+ {
+ public:
+ Data(GLenum shaderType);
+ ~Data();
+
+ const std::string &getLabel() const { return mLabel; }
+
+ const std::string &getSource() const { return mSource; }
+ const std::string &getTranslatedSource() const { return mTranslatedSource; }
+
+ GLenum getShaderType() const { return mShaderType; }
+ int getShaderVersion() const { return mShaderVersion; }
+
+ const std::vector<sh::Varying> &getVaryings() const { return mVaryings; }
+ const std::vector<sh::Uniform> &getUniforms() const { return mUniforms; }
+ const std::vector<sh::InterfaceBlock> &getInterfaceBlocks() const
+ {
+ return mInterfaceBlocks;
+ }
+ const std::vector<sh::Attribute> &getActiveAttributes() const { return mActiveAttributes; }
+ const std::vector<sh::OutputVariable> &getActiveOutputVariables() const
+ {
+ return mActiveOutputVariables;
+ }
+
+ private:
+ friend class Shader;
+
+ std::string mLabel;
+
+ GLenum mShaderType;
+ int mShaderVersion;
+ std::string mTranslatedSource;
+ std::string mSource;
+
+ std::vector<sh::Varying> mVaryings;
+ std::vector<sh::Uniform> mUniforms;
+ std::vector<sh::InterfaceBlock> mInterfaceBlocks;
+ std::vector<sh::Attribute> mActiveAttributes;
+ std::vector<sh::OutputVariable> mActiveOutputVariables;
+ };
+
+ Shader(ResourceManager *manager,
+ rx::ImplFactory *implFactory,
+ const gl::Limitations &rendererLimitations,
+ GLenum type,
+ GLuint handle);
virtual ~Shader();
+ void setLabel(const std::string &label) override;
+ const std::string &getLabel() const override;
+
GLenum getType() const { return mType; }
GLuint getHandle() const;
- rx::ShaderImpl *getImplementation() { return mShader; }
- const rx::ShaderImpl *getImplementation() const { return mShader; }
+ const rx::ShaderImpl *getImplementation() const { return mImplementation; }
void deleteSource();
void setSource(GLsizei count, const char *const *string, const GLint *length);
@@ -73,6 +106,8 @@ class Shader : angle::NonCopyable
int getSourceLength() const;
void getSource(GLsizei bufSize, GLsizei *length, char *buffer) const;
int getTranslatedSourceLength() const;
+ int getTranslatedSourceWithDebugInfoLength() const;
+ const std::string &getTranslatedSource() const { return mData.getTranslatedSource(); }
void getTranslatedSource(GLsizei bufSize, GLsizei *length, char *buffer) const;
void getTranslatedSourceWithDebugInfo(GLsizei bufSize, GLsizei *length, char *buffer) const;
@@ -85,34 +120,33 @@ class Shader : angle::NonCopyable
bool isFlaggedForDeletion() const;
void flagForDeletion();
- const std::vector<gl::PackedVarying> &getVaryings() const;
+ int getShaderVersion() const;
+
+ const std::vector<sh::Varying> &getVaryings() const;
const std::vector<sh::Uniform> &getUniforms() const;
const std::vector<sh::InterfaceBlock> &getInterfaceBlocks() const;
const std::vector<sh::Attribute> &getActiveAttributes() const;
- const std::vector<sh::Attribute> &getActiveOutputVariables() const;
-
- std::vector<gl::PackedVarying> &getVaryings();
- std::vector<sh::Uniform> &getUniforms();
- std::vector<sh::InterfaceBlock> &getInterfaceBlocks();
- std::vector<sh::Attribute> &getActiveAttributes();
- std::vector<sh::Attribute> &getActiveOutputVariables();
+ const std::vector<sh::OutputVariable> &getActiveOutputVariables() const;
int getSemanticIndex(const std::string &attributeName) const;
private:
static void getSourceImpl(const std::string &source, GLsizei bufSize, GLsizei *length, char *buffer);
- rx::ShaderImpl *mShader;
+ Data mData;
+ rx::ShaderImpl *mImplementation;
+ const gl::Limitations &mRendererLimitations;
const GLuint mHandle;
const GLenum mType;
- std::string mSource;
unsigned int mRefCount; // Number of program objects this shader is attached to
bool mDeleteStatus; // Flag to indicate that the shader can be deleted when no longer in use
bool mCompiled; // Indicates if this shader has been successfully compiled
+ std::string mInfoLog;
ResourceManager *mResourceManager;
};
+bool CompareShaderVar(const sh::ShaderVariable &x, const sh::ShaderVariable &y);
}
#endif // LIBANGLE_SHADER_H_
diff --git a/src/3rdparty/angle/src/libANGLE/State.cpp b/src/3rdparty/angle/src/libANGLE/State.cpp
index 4c044d2950..a1437b838b 100644
--- a/src/3rdparty/angle/src/libANGLE/State.cpp
+++ b/src/3rdparty/angle/src/libANGLE/State.cpp
@@ -8,8 +8,10 @@
#include "libANGLE/State.h"
+#include "common/BitSetIterator.h"
#include "libANGLE/Context.h"
#include "libANGLE/Caps.h"
+#include "libANGLE/Debug.h"
#include "libANGLE/Framebuffer.h"
#include "libANGLE/FramebufferAttachment.h"
#include "libANGLE/Query.h"
@@ -20,9 +22,57 @@ namespace gl
{
State::State()
-{
- mMaxDrawBuffers = 0;
- mMaxCombinedTextureImageUnits = 0;
+ : mMaxDrawBuffers(0),
+ mMaxCombinedTextureImageUnits(0),
+ mDepthClearValue(0),
+ mStencilClearValue(0),
+ mScissorTest(false),
+ mSampleCoverage(false),
+ mSampleCoverageValue(0),
+ mSampleCoverageInvert(false),
+ mStencilRef(0),
+ mStencilBackRef(0),
+ mLineWidth(0),
+ mGenerateMipmapHint(GL_NONE),
+ mFragmentShaderDerivativeHint(GL_NONE),
+ mNearZ(0),
+ mFarZ(0),
+ mReadFramebuffer(nullptr),
+ mDrawFramebuffer(nullptr),
+ mProgram(nullptr),
+ mVertexArray(nullptr),
+ mActiveSampler(0),
+ mPrimitiveRestart(false)
+{
+ // Initialize dirty bit masks
+ // TODO(jmadill): additional ES3 state
+ mUnpackStateBitMask.set(DIRTY_BIT_UNPACK_ALIGNMENT);
+ mUnpackStateBitMask.set(DIRTY_BIT_UNPACK_ROW_LENGTH);
+ mUnpackStateBitMask.set(DIRTY_BIT_UNPACK_IMAGE_HEIGHT);
+ mUnpackStateBitMask.set(DIRTY_BIT_UNPACK_SKIP_IMAGES);
+ mUnpackStateBitMask.set(DIRTY_BIT_UNPACK_SKIP_ROWS);
+ mUnpackStateBitMask.set(DIRTY_BIT_UNPACK_SKIP_PIXELS);
+
+ mPackStateBitMask.set(DIRTY_BIT_PACK_ALIGNMENT);
+ mPackStateBitMask.set(DIRTY_BIT_PACK_REVERSE_ROW_ORDER);
+ mPackStateBitMask.set(DIRTY_BIT_PACK_ROW_LENGTH);
+ mPackStateBitMask.set(DIRTY_BIT_PACK_SKIP_ROWS);
+ mPackStateBitMask.set(DIRTY_BIT_PACK_SKIP_PIXELS);
+
+ mClearStateBitMask.set(DIRTY_BIT_RASTERIZER_DISCARD_ENABLED);
+ mClearStateBitMask.set(DIRTY_BIT_SCISSOR_TEST_ENABLED);
+ mClearStateBitMask.set(DIRTY_BIT_SCISSOR);
+ mClearStateBitMask.set(DIRTY_BIT_VIEWPORT);
+ mClearStateBitMask.set(DIRTY_BIT_CLEAR_COLOR);
+ mClearStateBitMask.set(DIRTY_BIT_CLEAR_DEPTH);
+ mClearStateBitMask.set(DIRTY_BIT_CLEAR_STENCIL);
+ mClearStateBitMask.set(DIRTY_BIT_COLOR_MASK);
+ mClearStateBitMask.set(DIRTY_BIT_DEPTH_MASK);
+ mClearStateBitMask.set(DIRTY_BIT_STENCIL_WRITEMASK_FRONT);
+ mClearStateBitMask.set(DIRTY_BIT_STENCIL_WRITEMASK_BACK);
+
+ mBlitStateBitMask.set(DIRTY_BIT_SCISSOR_TEST_ENABLED);
+ mBlitStateBitMask.set(DIRTY_BIT_SCISSOR);
}
State::~State()
@@ -30,7 +80,10 @@ State::~State()
reset();
}
-void State::initialize(const Caps& caps, GLuint clientVersion)
+void State::initialize(const Caps &caps,
+ const Extensions &extensions,
+ GLuint clientVersion,
+ bool debug)
{
mMaxDrawBuffers = caps.maxDrawBuffers;
mMaxCombinedTextureImageUnits = caps.maxCombinedTextureImageUnits;
@@ -112,15 +165,9 @@ void State::initialize(const Caps& caps, GLuint clientVersion)
mActiveSampler = 0;
- const GLfloat defaultFloatValues[] = { 0.0f, 0.0f, 0.0f, 1.0f };
mVertexAttribCurrentValues.resize(caps.maxVertexAttributes);
- for (size_t attribIndex = 0; attribIndex < mVertexAttribCurrentValues.size(); ++attribIndex)
- {
- mVertexAttribCurrentValues[attribIndex].setFloatValues(defaultFloatValues);
- }
mUniformBuffers.resize(caps.maxCombinedUniformBlocks);
- mTransformFeedbackBuffers.resize(caps.maxTransformFeedbackSeparateAttributes);
mSamplerTextures[GL_TEXTURE_2D].resize(caps.maxCombinedTextureImageUnits);
mSamplerTextures[GL_TEXTURE_CUBE_MAP].resize(caps.maxCombinedTextureImageUnits);
@@ -133,16 +180,20 @@ void State::initialize(const Caps& caps, GLuint clientVersion)
mSamplers.resize(caps.maxCombinedTextureImageUnits);
- mActiveQueries[GL_ANY_SAMPLES_PASSED].set(NULL);
- mActiveQueries[GL_ANY_SAMPLES_PASSED_CONSERVATIVE].set(NULL);
- mActiveQueries[GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN].set(NULL);
+ mActiveQueries[GL_ANY_SAMPLES_PASSED].set(nullptr);
+ mActiveQueries[GL_ANY_SAMPLES_PASSED_CONSERVATIVE].set(nullptr);
+ mActiveQueries[GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN].set(nullptr);
+ mActiveQueries[GL_TIME_ELAPSED_EXT].set(nullptr);
- mProgram = NULL;
+ mProgram = nullptr;
- mReadFramebuffer = NULL;
- mDrawFramebuffer = NULL;
+ mReadFramebuffer = nullptr;
+ mDrawFramebuffer = nullptr;
mPrimitiveRestart = false;
+
+ mDebug.setOutputEnabled(debug);
+ mDebug.setMaxLoggedMessages(extensions.maxDebugLoggedMessages);
}
void State::reset()
@@ -177,17 +228,11 @@ void State::reset()
}
mGenericUniformBuffer.set(NULL);
- mGenericTransformFeedbackBuffer.set(NULL);
for (BufferVector::iterator bufItr = mUniformBuffers.begin(); bufItr != mUniformBuffers.end(); ++bufItr)
{
bufItr->set(NULL);
}
- for (BufferVector::iterator bufItr = mTransformFeedbackBuffers.begin(); bufItr != mTransformFeedbackBuffers.end(); ++bufItr)
- {
- bufItr->set(NULL);
- }
-
mCopyReadBuffer.set(NULL);
mCopyWriteBuffer.set(NULL);
@@ -195,6 +240,9 @@ void State::reset()
mUnpack.pixelBuffer.set(NULL);
mProgram = NULL;
+
+ // TODO(jmadill): Is this necessary?
+ setAllDirtyBits();
}
const RasterizerState &State::getRasterizerState() const
@@ -218,16 +266,19 @@ void State::setColorClearValue(float red, float green, float blue, float alpha)
mColorClearValue.green = green;
mColorClearValue.blue = blue;
mColorClearValue.alpha = alpha;
+ mDirtyBits.set(DIRTY_BIT_CLEAR_COLOR);
}
void State::setDepthClearValue(float depth)
{
mDepthClearValue = depth;
+ mDirtyBits.set(DIRTY_BIT_CLEAR_DEPTH);
}
void State::setStencilClearValue(int stencil)
{
mStencilClearValue = stencil;
+ mDirtyBits.set(DIRTY_BIT_CLEAR_STENCIL);
}
void State::setColorMask(bool red, bool green, bool blue, bool alpha)
@@ -236,11 +287,13 @@ void State::setColorMask(bool red, bool green, bool blue, bool alpha)
mBlend.colorMaskGreen = green;
mBlend.colorMaskBlue = blue;
mBlend.colorMaskAlpha = alpha;
+ mDirtyBits.set(DIRTY_BIT_COLOR_MASK);
}
void State::setDepthMask(bool mask)
{
mDepthStencil.depthMask = mask;
+ mDirtyBits.set(DIRTY_BIT_DEPTH_MASK);
}
bool State::isRasterizerDiscardEnabled() const
@@ -251,6 +304,7 @@ bool State::isRasterizerDiscardEnabled() const
void State::setRasterizerDiscard(bool enabled)
{
mRasterizer.rasterizerDiscard = enabled;
+ mDirtyBits.set(DIRTY_BIT_RASTERIZER_DISCARD_ENABLED);
}
bool State::isCullFaceEnabled() const
@@ -261,16 +315,19 @@ bool State::isCullFaceEnabled() const
void State::setCullFace(bool enabled)
{
mRasterizer.cullFace = enabled;
+ mDirtyBits.set(DIRTY_BIT_CULL_FACE_ENABLED);
}
void State::setCullMode(GLenum mode)
{
mRasterizer.cullMode = mode;
+ mDirtyBits.set(DIRTY_BIT_CULL_FACE);
}
void State::setFrontFace(GLenum front)
{
mRasterizer.frontFace = front;
+ mDirtyBits.set(DIRTY_BIT_FRONT_FACE);
}
bool State::isDepthTestEnabled() const
@@ -281,23 +338,30 @@ bool State::isDepthTestEnabled() const
void State::setDepthTest(bool enabled)
{
mDepthStencil.depthTest = enabled;
+ mDirtyBits.set(DIRTY_BIT_DEPTH_TEST_ENABLED);
}
void State::setDepthFunc(GLenum depthFunc)
{
mDepthStencil.depthFunc = depthFunc;
+ mDirtyBits.set(DIRTY_BIT_DEPTH_FUNC);
}
void State::setDepthRange(float zNear, float zFar)
{
mNearZ = zNear;
mFarZ = zFar;
+ mDirtyBits.set(DIRTY_BIT_DEPTH_RANGE);
+}
+
+float State::getNearPlane() const
+{
+ return mNearZ;
}
-void State::getDepthRange(float *zNear, float *zFar) const
+float State::getFarPlane() const
{
- *zNear = mNearZ;
- *zFar = mFarZ;
+ return mFarZ;
}
bool State::isBlendEnabled() const
@@ -308,6 +372,7 @@ bool State::isBlendEnabled() const
void State::setBlend(bool enabled)
{
mBlend.blend = enabled;
+ mDirtyBits.set(DIRTY_BIT_BLEND_ENABLED);
}
void State::setBlendFactors(GLenum sourceRGB, GLenum destRGB, GLenum sourceAlpha, GLenum destAlpha)
@@ -316,6 +381,7 @@ void State::setBlendFactors(GLenum sourceRGB, GLenum destRGB, GLenum sourceAlpha
mBlend.destBlendRGB = destRGB;
mBlend.sourceBlendAlpha = sourceAlpha;
mBlend.destBlendAlpha = destAlpha;
+ mDirtyBits.set(DIRTY_BIT_BLEND_FUNCS);
}
void State::setBlendColor(float red, float green, float blue, float alpha)
@@ -324,12 +390,14 @@ void State::setBlendColor(float red, float green, float blue, float alpha)
mBlendColor.green = green;
mBlendColor.blue = blue;
mBlendColor.alpha = alpha;
+ mDirtyBits.set(DIRTY_BIT_BLEND_COLOR);
}
void State::setBlendEquation(GLenum rgbEquation, GLenum alphaEquation)
{
mBlend.blendEquationRGB = rgbEquation;
mBlend.blendEquationAlpha = alphaEquation;
+ mDirtyBits.set(DIRTY_BIT_BLEND_EQUATIONS);
}
const ColorF &State::getBlendColor() const
@@ -345,6 +413,7 @@ bool State::isStencilTestEnabled() const
void State::setStencilTest(bool enabled)
{
mDepthStencil.stencilTest = enabled;
+ mDirtyBits.set(DIRTY_BIT_STENCIL_TEST_ENABLED);
}
void State::setStencilParams(GLenum stencilFunc, GLint stencilRef, GLuint stencilMask)
@@ -352,6 +421,7 @@ void State::setStencilParams(GLenum stencilFunc, GLint stencilRef, GLuint stenci
mDepthStencil.stencilFunc = stencilFunc;
mStencilRef = (stencilRef > 0) ? stencilRef : 0;
mDepthStencil.stencilMask = stencilMask;
+ mDirtyBits.set(DIRTY_BIT_STENCIL_FUNCS_FRONT);
}
void State::setStencilBackParams(GLenum stencilBackFunc, GLint stencilBackRef, GLuint stencilBackMask)
@@ -359,16 +429,19 @@ void State::setStencilBackParams(GLenum stencilBackFunc, GLint stencilBackRef, G
mDepthStencil.stencilBackFunc = stencilBackFunc;
mStencilBackRef = (stencilBackRef > 0) ? stencilBackRef : 0;
mDepthStencil.stencilBackMask = stencilBackMask;
+ mDirtyBits.set(DIRTY_BIT_STENCIL_FUNCS_BACK);
}
void State::setStencilWritemask(GLuint stencilWritemask)
{
mDepthStencil.stencilWritemask = stencilWritemask;
+ mDirtyBits.set(DIRTY_BIT_STENCIL_WRITEMASK_FRONT);
}
void State::setStencilBackWritemask(GLuint stencilBackWritemask)
{
mDepthStencil.stencilBackWritemask = stencilBackWritemask;
+ mDirtyBits.set(DIRTY_BIT_STENCIL_WRITEMASK_BACK);
}
void State::setStencilOperations(GLenum stencilFail, GLenum stencilPassDepthFail, GLenum stencilPassDepthPass)
@@ -376,6 +449,7 @@ void State::setStencilOperations(GLenum stencilFail, GLenum stencilPassDepthFail
mDepthStencil.stencilFail = stencilFail;
mDepthStencil.stencilPassDepthFail = stencilPassDepthFail;
mDepthStencil.stencilPassDepthPass = stencilPassDepthPass;
+ mDirtyBits.set(DIRTY_BIT_STENCIL_OPS_FRONT);
}
void State::setStencilBackOperations(GLenum stencilBackFail, GLenum stencilBackPassDepthFail, GLenum stencilBackPassDepthPass)
@@ -383,6 +457,7 @@ void State::setStencilBackOperations(GLenum stencilBackFail, GLenum stencilBackP
mDepthStencil.stencilBackFail = stencilBackFail;
mDepthStencil.stencilBackPassDepthFail = stencilBackPassDepthFail;
mDepthStencil.stencilBackPassDepthPass = stencilBackPassDepthPass;
+ mDirtyBits.set(DIRTY_BIT_STENCIL_OPS_BACK);
}
GLint State::getStencilRef() const
@@ -402,7 +477,8 @@ bool State::isPolygonOffsetFillEnabled() const
void State::setPolygonOffsetFill(bool enabled)
{
- mRasterizer.polygonOffsetFill = enabled;
+ mRasterizer.polygonOffsetFill = enabled;
+ mDirtyBits.set(DIRTY_BIT_POLYGON_OFFSET_FILL_ENABLED);
}
void State::setPolygonOffsetParams(GLfloat factor, GLfloat units)
@@ -410,6 +486,7 @@ void State::setPolygonOffsetParams(GLfloat factor, GLfloat units)
// An application can pass NaN values here, so handle this gracefully
mRasterizer.polygonOffsetFactor = factor != factor ? 0.0f : factor;
mRasterizer.polygonOffsetUnits = units != units ? 0.0f : units;
+ mDirtyBits.set(DIRTY_BIT_POLYGON_OFFSET);
}
bool State::isSampleAlphaToCoverageEnabled() const
@@ -420,6 +497,7 @@ bool State::isSampleAlphaToCoverageEnabled() const
void State::setSampleAlphaToCoverage(bool enabled)
{
mBlend.sampleAlphaToCoverage = enabled;
+ mDirtyBits.set(DIRTY_BIT_SAMPLE_ALPHA_TO_COVERAGE_ENABLED);
}
bool State::isSampleCoverageEnabled() const
@@ -430,20 +508,24 @@ bool State::isSampleCoverageEnabled() const
void State::setSampleCoverage(bool enabled)
{
mSampleCoverage = enabled;
+ mDirtyBits.set(DIRTY_BIT_SAMPLE_COVERAGE_ENABLED);
}
void State::setSampleCoverageParams(GLclampf value, bool invert)
{
mSampleCoverageValue = value;
mSampleCoverageInvert = invert;
+ mDirtyBits.set(DIRTY_BIT_SAMPLE_COVERAGE);
}
-void State::getSampleCoverageParams(GLclampf *value, bool *invert) const
+GLclampf State::getSampleCoverageValue() const
{
- ASSERT(value != NULL && invert != NULL);
+ return mSampleCoverageValue;
+}
- *value = mSampleCoverageValue;
- *invert = mSampleCoverageInvert;
+bool State::getSampleCoverageInvert() const
+{
+ return mSampleCoverageInvert;
}
bool State::isScissorTestEnabled() const
@@ -454,6 +536,7 @@ bool State::isScissorTestEnabled() const
void State::setScissorTest(bool enabled)
{
mScissorTest = enabled;
+ mDirtyBits.set(DIRTY_BIT_SCISSOR_TEST_ENABLED);
}
void State::setScissorParams(GLint x, GLint y, GLsizei width, GLsizei height)
@@ -462,6 +545,7 @@ void State::setScissorParams(GLint x, GLint y, GLsizei width, GLsizei height)
mScissor.y = y;
mScissor.width = width;
mScissor.height = height;
+ mDirtyBits.set(DIRTY_BIT_SCISSOR);
}
const Rectangle &State::getScissor() const
@@ -477,6 +561,7 @@ bool State::isDitherEnabled() const
void State::setDither(bool enabled)
{
mBlend.dither = enabled;
+ mDirtyBits.set(DIRTY_BIT_DITHER_ENABLED);
}
bool State::isPrimitiveRestartEnabled() const
@@ -487,6 +572,7 @@ bool State::isPrimitiveRestartEnabled() const
void State::setPrimitiveRestart(bool enabled)
{
mPrimitiveRestart = enabled;
+ mDirtyBits.set(DIRTY_BIT_PRIMITIVE_RESTART_ENABLED);
}
void State::setEnableFeature(GLenum feature, bool enabled)
@@ -504,6 +590,12 @@ void State::setEnableFeature(GLenum feature, bool enabled)
case GL_DITHER: setDither(enabled); break;
case GL_PRIMITIVE_RESTART_FIXED_INDEX: setPrimitiveRestart(enabled); break;
case GL_RASTERIZER_DISCARD: setRasterizerDiscard(enabled); break;
+ case GL_DEBUG_OUTPUT_SYNCHRONOUS:
+ mDebug.setOutputSynchronous(enabled);
+ break;
+ case GL_DEBUG_OUTPUT:
+ mDebug.setOutputEnabled(enabled);
+ break;
default: UNREACHABLE();
}
}
@@ -523,6 +615,10 @@ bool State::getEnableFeature(GLenum feature)
case GL_DITHER: return isDitherEnabled();
case GL_PRIMITIVE_RESTART_FIXED_INDEX: return isPrimitiveRestartEnabled();
case GL_RASTERIZER_DISCARD: return isRasterizerDiscardEnabled();
+ case GL_DEBUG_OUTPUT_SYNCHRONOUS:
+ return mDebug.isOutputSynchronous();
+ case GL_DEBUG_OUTPUT:
+ return mDebug.isOutputEnabled();
default: UNREACHABLE(); return false;
}
}
@@ -530,16 +626,24 @@ bool State::getEnableFeature(GLenum feature)
void State::setLineWidth(GLfloat width)
{
mLineWidth = width;
+ mDirtyBits.set(DIRTY_BIT_LINE_WIDTH);
+}
+
+float State::getLineWidth() const
+{
+ return mLineWidth;
}
void State::setGenerateMipmapHint(GLenum hint)
{
mGenerateMipmapHint = hint;
+ mDirtyBits.set(DIRTY_BIT_GENERATE_MIPMAP_HINT);
}
void State::setFragmentShaderDerivativeHint(GLenum hint)
{
mFragmentShaderDerivativeHint = hint;
+ mDirtyBits.set(DIRTY_BIT_SHADER_DERIVATIVE_HINT);
// TODO: Propagate the hint to shader translator so we can write
// ddx, ddx_coarse, or ddx_fine depending on the hint.
// Ignore for now. It is valid for implementations to ignore hint.
@@ -551,6 +655,7 @@ void State::setViewportParams(GLint x, GLint y, GLsizei width, GLsizei height)
mViewport.y = y;
mViewport.width = width;
mViewport.height = height;
+ mDirtyBits.set(DIRTY_BIT_VIEWPORT);
}
const Rectangle &State::getViewport() const
@@ -565,7 +670,7 @@ void State::setActiveSampler(unsigned int active)
unsigned int State::getActiveSampler() const
{
- return mActiveSampler;
+ return static_cast<unsigned int>(mActiveSampler);
}
void State::setSamplerTexture(GLenum type, Texture *texture)
@@ -573,10 +678,16 @@ void State::setSamplerTexture(GLenum type, Texture *texture)
mSamplerTextures[type][mActiveSampler].set(texture);
}
+Texture *State::getTargetTexture(GLenum target) const
+{
+ return getSamplerTexture(static_cast<unsigned int>(mActiveSampler), target);
+}
+
Texture *State::getSamplerTexture(unsigned int sampler, GLenum type) const
{
const auto it = mSamplerTextures.find(type);
ASSERT(it != mSamplerTextures.end());
+ ASSERT(sampler < it->second.size());
return it->second[sampler].get();
}
@@ -584,6 +695,7 @@ GLuint State::getSamplerTextureId(unsigned int sampler, GLenum type) const
{
const auto it = mSamplerTextures.find(type);
ASSERT(it != mSamplerTextures.end());
+ ASSERT(sampler < it->second.size());
return it->second[sampler].id();
}
@@ -633,9 +745,8 @@ void State::detachTexture(const TextureMap &zeroTextures, GLuint texture)
void State::initializeZeroTextures(const TextureMap &zeroTextures)
{
- for (auto it = zeroTextures.cbegin(); it != zeroTextures.cend(); ++it)
+ for (const auto &zeroTexture : zeroTextures)
{
- const auto &zeroTexture = *it;
auto &samplerTextureArray = mSamplerTextures[zeroTexture.first];
for (size_t textureUnit = 0; textureUnit < samplerTextureArray.size(); ++textureUnit)
@@ -725,22 +836,44 @@ void State::detachRenderbuffer(GLuint renderbuffer)
void State::setReadFramebufferBinding(Framebuffer *framebuffer)
{
+ if (mReadFramebuffer == framebuffer)
+ return;
+
mReadFramebuffer = framebuffer;
+ mDirtyBits.set(DIRTY_BIT_READ_FRAMEBUFFER_BINDING);
+
+ if (mReadFramebuffer && mReadFramebuffer->hasAnyDirtyBit())
+ {
+ mDirtyObjects.set(DIRTY_OBJECT_READ_FRAMEBUFFER);
+ }
}
void State::setDrawFramebufferBinding(Framebuffer *framebuffer)
{
+ if (mDrawFramebuffer == framebuffer)
+ return;
+
mDrawFramebuffer = framebuffer;
+ mDirtyBits.set(DIRTY_BIT_DRAW_FRAMEBUFFER_BINDING);
+
+ if (mDrawFramebuffer && mDrawFramebuffer->hasAnyDirtyBit())
+ {
+ mDirtyObjects.set(DIRTY_OBJECT_DRAW_FRAMEBUFFER);
+ }
}
Framebuffer *State::getTargetFramebuffer(GLenum target) const
{
switch (target)
{
- case GL_READ_FRAMEBUFFER_ANGLE: return mReadFramebuffer;
- case GL_DRAW_FRAMEBUFFER_ANGLE:
- case GL_FRAMEBUFFER: return mDrawFramebuffer;
- default: UNREACHABLE(); return NULL;
+ case GL_READ_FRAMEBUFFER_ANGLE:
+ return mReadFramebuffer;
+ case GL_DRAW_FRAMEBUFFER_ANGLE:
+ case GL_FRAMEBUFFER:
+ return mDrawFramebuffer;
+ default:
+ UNREACHABLE();
+ return NULL;
}
}
@@ -766,9 +899,10 @@ const Framebuffer *State::getDrawFramebuffer() const
bool State::removeReadFramebufferBinding(GLuint framebuffer)
{
- if (mReadFramebuffer->id() == framebuffer)
+ if (mReadFramebuffer != nullptr &&
+ mReadFramebuffer->id() == framebuffer)
{
- mReadFramebuffer = NULL;
+ setReadFramebufferBinding(nullptr);
return true;
}
@@ -777,9 +911,10 @@ bool State::removeReadFramebufferBinding(GLuint framebuffer)
bool State::removeDrawFramebufferBinding(GLuint framebuffer)
{
- if (mDrawFramebuffer->id() == framebuffer)
+ if (mReadFramebuffer != nullptr &&
+ mDrawFramebuffer->id() == framebuffer)
{
- mDrawFramebuffer = NULL;
+ setDrawFramebufferBinding(nullptr);
return true;
}
@@ -789,6 +924,12 @@ bool State::removeDrawFramebufferBinding(GLuint framebuffer)
void State::setVertexArrayBinding(VertexArray *vertexArray)
{
mVertexArray = vertexArray;
+ mDirtyBits.set(DIRTY_BIT_VERTEX_ARRAY_BINDING);
+
+ if (mVertexArray && mVertexArray->hasAnyDirtyBit())
+ {
+ mDirtyObjects.set(DIRTY_OBJECT_VERTEX_ARRAY);
+ }
}
GLuint State::getVertexArrayId() const
@@ -808,6 +949,8 @@ bool State::removeVertexArrayBinding(GLuint vertexArray)
if (mVertexArray->id() == vertexArray)
{
mVertexArray = NULL;
+ mDirtyBits.set(DIRTY_BIT_VERTEX_ARRAY_BINDING);
+ mDirtyObjects.set(DIRTY_OBJECT_VERTEX_ARRAY);
return true;
}
@@ -850,7 +993,7 @@ TransformFeedback *State::getCurrentTransformFeedback() const
bool State::isTransformFeedbackActiveUnpaused() const
{
gl::TransformFeedback *curTransformFeedback = getCurrentTransformFeedback();
- return curTransformFeedback && curTransformFeedback->isStarted() && !curTransformFeedback->isPaused();
+ return curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused();
}
void State::detachTransformFeedback(GLuint transformFeedback)
@@ -863,10 +1006,22 @@ void State::detachTransformFeedback(GLuint transformFeedback)
bool State::isQueryActive() const
{
- for (State::ActiveQueryMap::const_iterator i = mActiveQueries.begin();
- i != mActiveQueries.end(); i++)
+ for (auto &iter : mActiveQueries)
{
- if (i->second.get() != NULL)
+ if (iter.second.get() != NULL)
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool State::isQueryActive(Query *query) const
+{
+ for (auto &iter : mActiveQueries)
+ {
+ if (iter.second.get() == query)
{
return true;
}
@@ -906,17 +1061,6 @@ GLuint State::getArrayBufferId() const
return mArrayBuffer.id();
}
-bool State::removeArrayBufferBinding(GLuint buffer)
-{
- if (mArrayBuffer.id() == buffer)
- {
- mArrayBuffer.set(NULL);
- return true;
- }
-
- return false;
-}
-
void State::setGenericUniformBufferBinding(Buffer *buffer)
{
mGenericUniformBuffer.set(buffer);
@@ -927,68 +1071,10 @@ void State::setIndexedUniformBufferBinding(GLuint index, Buffer *buffer, GLintpt
mUniformBuffers[index].set(buffer, offset, size);
}
-GLuint State::getIndexedUniformBufferId(GLuint index) const
-{
- ASSERT(static_cast<size_t>(index) < mUniformBuffers.size());
-
- return mUniformBuffers[index].id();
-}
-
-Buffer *State::getIndexedUniformBuffer(GLuint index) const
+const OffsetBindingPointer<Buffer> &State::getIndexedUniformBuffer(size_t index) const
{
ASSERT(static_cast<size_t>(index) < mUniformBuffers.size());
-
- return mUniformBuffers[index].get();
-}
-
-GLintptr State::getIndexedUniformBufferOffset(GLuint index) const
-{
- ASSERT(static_cast<size_t>(index) < mUniformBuffers.size());
-
- return mUniformBuffers[index].getOffset();
-}
-
-GLsizeiptr State::getIndexedUniformBufferSize(GLuint index) const
-{
- ASSERT(static_cast<size_t>(index) < mUniformBuffers.size());
-
- return mUniformBuffers[index].getSize();
-}
-
-void State::setGenericTransformFeedbackBufferBinding(Buffer *buffer)
-{
- mGenericTransformFeedbackBuffer.set(buffer);
-}
-
-void State::setIndexedTransformFeedbackBufferBinding(GLuint index, Buffer *buffer, GLintptr offset, GLsizeiptr size)
-{
- mTransformFeedbackBuffers[index].set(buffer, offset, size);
-}
-
-GLuint State::getIndexedTransformFeedbackBufferId(GLuint index) const
-{
- ASSERT(static_cast<size_t>(index) < mTransformFeedbackBuffers.size());
-
- return mTransformFeedbackBuffers[index].id();
-}
-
-Buffer *State::getIndexedTransformFeedbackBuffer(GLuint index) const
-{
- ASSERT(static_cast<size_t>(index) < mTransformFeedbackBuffers.size());
-
- return mTransformFeedbackBuffers[index].get();
-}
-
-GLuint State::getIndexedTransformFeedbackBufferOffset(GLuint index) const
-{
- ASSERT(static_cast<size_t>(index) < mTransformFeedbackBuffers.size());
-
- return mTransformFeedbackBuffers[index].getOffset();
-}
-
-size_t State::getTransformFeedbackBufferIndexRange() const
-{
- return mTransformFeedbackBuffers.size();
+ return mUniformBuffers[index];
}
void State::setCopyReadBufferBinding(Buffer *buffer)
@@ -1018,42 +1104,81 @@ Buffer *State::getTargetBuffer(GLenum target) const
case GL_ARRAY_BUFFER: return mArrayBuffer.get();
case GL_COPY_READ_BUFFER: return mCopyReadBuffer.get();
case GL_COPY_WRITE_BUFFER: return mCopyWriteBuffer.get();
- case GL_ELEMENT_ARRAY_BUFFER: return getVertexArray()->getElementArrayBuffer();
+ case GL_ELEMENT_ARRAY_BUFFER: return getVertexArray()->getElementArrayBuffer().get();
case GL_PIXEL_PACK_BUFFER: return mPack.pixelBuffer.get();
case GL_PIXEL_UNPACK_BUFFER: return mUnpack.pixelBuffer.get();
- case GL_TRANSFORM_FEEDBACK_BUFFER: return mGenericTransformFeedbackBuffer.get();
+ case GL_TRANSFORM_FEEDBACK_BUFFER: return mTransformFeedback->getGenericBuffer().get();
case GL_UNIFORM_BUFFER: return mGenericUniformBuffer.get();
default: UNREACHABLE(); return NULL;
}
}
+void State::detachBuffer(GLuint bufferName)
+{
+ BindingPointer<Buffer> *buffers[] = {&mArrayBuffer, &mCopyReadBuffer,
+ &mCopyWriteBuffer, &mPack.pixelBuffer,
+ &mUnpack.pixelBuffer, &mGenericUniformBuffer};
+ for (auto buffer : buffers)
+ {
+ if (buffer->id() == bufferName)
+ {
+ buffer->set(nullptr);
+ }
+ }
+
+ TransformFeedback *curTransformFeedback = getCurrentTransformFeedback();
+ if (curTransformFeedback)
+ {
+ curTransformFeedback->detachBuffer(bufferName);
+ }
+
+ getVertexArray()->detachBuffer(bufferName);
+}
+
void State::setEnableVertexAttribArray(unsigned int attribNum, bool enabled)
{
getVertexArray()->enableAttribute(attribNum, enabled);
+ mDirtyObjects.set(DIRTY_OBJECT_VERTEX_ARRAY);
}
void State::setVertexAttribf(GLuint index, const GLfloat values[4])
{
ASSERT(static_cast<size_t>(index) < mVertexAttribCurrentValues.size());
mVertexAttribCurrentValues[index].setFloatValues(values);
+ mDirtyBits.set(DIRTY_BIT_CURRENT_VALUE_0 + index);
}
void State::setVertexAttribu(GLuint index, const GLuint values[4])
{
ASSERT(static_cast<size_t>(index) < mVertexAttribCurrentValues.size());
mVertexAttribCurrentValues[index].setUnsignedIntValues(values);
+ mDirtyBits.set(DIRTY_BIT_CURRENT_VALUE_0 + index);
}
void State::setVertexAttribi(GLuint index, const GLint values[4])
{
ASSERT(static_cast<size_t>(index) < mVertexAttribCurrentValues.size());
mVertexAttribCurrentValues[index].setIntValues(values);
+ mDirtyBits.set(DIRTY_BIT_CURRENT_VALUE_0 + index);
}
-void State::setVertexAttribState(unsigned int attribNum, Buffer *boundBuffer, GLint size, GLenum type, bool normalized,
- bool pureInteger, GLsizei stride, const void *pointer)
+void State::setVertexAttribState(unsigned int attribNum,
+ Buffer *boundBuffer,
+ GLint size,
+ GLenum type,
+ bool normalized,
+ bool pureInteger,
+ GLsizei stride,
+ const void *pointer)
{
getVertexArray()->setAttributeState(attribNum, boundBuffer, size, type, normalized, pureInteger, stride, pointer);
+ mDirtyObjects.set(DIRTY_OBJECT_VERTEX_ARRAY);
+}
+
+void State::setVertexAttribDivisor(GLuint index, GLuint divisor)
+{
+ getVertexArray()->setVertexAttribDivisor(index, divisor);
+ mDirtyObjects.set(DIRTY_OBJECT_VERTEX_ARRAY);
}
const VertexAttribCurrentValueData &State::getVertexAttribCurrentValue(unsigned int attribNum) const
@@ -1070,6 +1195,7 @@ const void *State::getVertexAttribPointer(unsigned int attribNum) const
void State::setPackAlignment(GLint alignment)
{
mPack.alignment = alignment;
+ mDirtyBits.set(DIRTY_BIT_PACK_ALIGNMENT);
}
GLint State::getPackAlignment() const
@@ -1080,6 +1206,7 @@ GLint State::getPackAlignment() const
void State::setPackReverseRowOrder(bool reverseRowOrder)
{
mPack.reverseRowOrder = reverseRowOrder;
+ mDirtyBits.set(DIRTY_BIT_PACK_REVERSE_ROW_ORDER);
}
bool State::getPackReverseRowOrder() const
@@ -1087,6 +1214,39 @@ bool State::getPackReverseRowOrder() const
return mPack.reverseRowOrder;
}
+void State::setPackRowLength(GLint rowLength)
+{
+ mPack.rowLength = rowLength;
+ mDirtyBits.set(DIRTY_BIT_PACK_ROW_LENGTH);
+}
+
+GLint State::getPackRowLength() const
+{
+ return mPack.rowLength;
+}
+
+void State::setPackSkipRows(GLint skipRows)
+{
+ mPack.skipRows = skipRows;
+ mDirtyBits.set(DIRTY_BIT_PACK_SKIP_ROWS);
+}
+
+GLint State::getPackSkipRows() const
+{
+ return mPack.skipRows;
+}
+
+void State::setPackSkipPixels(GLint skipPixels)
+{
+ mPack.skipPixels = skipPixels;
+ mDirtyBits.set(DIRTY_BIT_PACK_SKIP_PIXELS);
+}
+
+GLint State::getPackSkipPixels() const
+{
+ return mPack.skipPixels;
+}
+
const PixelPackState &State::getPackState() const
{
return mPack;
@@ -1100,6 +1260,7 @@ PixelPackState &State::getPackState()
void State::setUnpackAlignment(GLint alignment)
{
mUnpack.alignment = alignment;
+ mDirtyBits.set(DIRTY_BIT_UNPACK_ALIGNMENT);
}
GLint State::getUnpackAlignment() const
@@ -1110,6 +1271,7 @@ GLint State::getUnpackAlignment() const
void State::setUnpackRowLength(GLint rowLength)
{
mUnpack.rowLength = rowLength;
+ mDirtyBits.set(DIRTY_BIT_UNPACK_ROW_LENGTH);
}
GLint State::getUnpackRowLength() const
@@ -1117,6 +1279,50 @@ GLint State::getUnpackRowLength() const
return mUnpack.rowLength;
}
+void State::setUnpackImageHeight(GLint imageHeight)
+{
+ mUnpack.imageHeight = imageHeight;
+ mDirtyBits.set(DIRTY_BIT_UNPACK_IMAGE_HEIGHT);
+}
+
+GLint State::getUnpackImageHeight() const
+{
+ return mUnpack.imageHeight;
+}
+
+void State::setUnpackSkipImages(GLint skipImages)
+{
+ mUnpack.skipImages = skipImages;
+ mDirtyBits.set(DIRTY_BIT_UNPACK_SKIP_IMAGES);
+}
+
+GLint State::getUnpackSkipImages() const
+{
+ return mUnpack.skipImages;
+}
+
+void State::setUnpackSkipRows(GLint skipRows)
+{
+ mUnpack.skipRows = skipRows;
+ mDirtyBits.set(DIRTY_BIT_UNPACK_SKIP_ROWS);
+}
+
+GLint State::getUnpackSkipRows() const
+{
+ return mUnpack.skipRows;
+}
+
+void State::setUnpackSkipPixels(GLint skipPixels)
+{
+ mUnpack.skipPixels = skipPixels;
+ mDirtyBits.set(DIRTY_BIT_UNPACK_SKIP_PIXELS);
+}
+
+GLint State::getUnpackSkipPixels() const
+{
+ return mUnpack.skipPixels;
+}
+
const PixelUnpackState &State::getUnpackState() const
{
return mUnpack;
@@ -1127,6 +1333,16 @@ PixelUnpackState &State::getUnpackState()
return mUnpack;
}
+const Debug &State::getDebug() const
+{
+ return mDebug;
+}
+
+Debug &State::getDebug()
+{
+ return mDebug;
+}
+
void State::getBooleanv(GLenum pname, GLboolean *params)
{
switch (pname)
@@ -1148,8 +1364,20 @@ void State::getBooleanv(GLenum pname, GLboolean *params)
case GL_DEPTH_TEST: *params = mDepthStencil.depthTest; break;
case GL_BLEND: *params = mBlend.blend; break;
case GL_DITHER: *params = mBlend.dither; break;
- case GL_TRANSFORM_FEEDBACK_ACTIVE: *params = getCurrentTransformFeedback()->isStarted(); break;
- case GL_TRANSFORM_FEEDBACK_PAUSED: *params = getCurrentTransformFeedback()->isPaused(); break;
+ case GL_TRANSFORM_FEEDBACK_ACTIVE: *params = getCurrentTransformFeedback()->isActive() ? GL_TRUE : GL_FALSE; break;
+ case GL_TRANSFORM_FEEDBACK_PAUSED: *params = getCurrentTransformFeedback()->isPaused() ? GL_TRUE : GL_FALSE; break;
+ case GL_PRIMITIVE_RESTART_FIXED_INDEX:
+ *params = mPrimitiveRestart;
+ break;
+ case GL_RASTERIZER_DISCARD:
+ *params = isRasterizerDiscardEnabled() ? GL_TRUE : GL_FALSE;
+ break;
+ case GL_DEBUG_OUTPUT_SYNCHRONOUS:
+ *params = mDebug.isOutputSynchronous() ? GL_TRUE : GL_FALSE;
+ break;
+ case GL_DEBUG_OUTPUT:
+ *params = mDebug.isOutputEnabled() ? GL_TRUE : GL_FALSE;
+ break;
default:
UNREACHABLE();
break;
@@ -1210,7 +1438,7 @@ void State::getIntegerv(const gl::Data &data, GLenum pname, GLint *params)
switch (pname)
{
case GL_ARRAY_BUFFER_BINDING: *params = mArrayBuffer.id(); break;
- case GL_ELEMENT_ARRAY_BUFFER_BINDING: *params = getVertexArray()->getElementArrayBufferId(); break;
+ case GL_ELEMENT_ARRAY_BUFFER_BINDING: *params = getVertexArray()->getElementArrayBuffer().id(); break;
//case GL_FRAMEBUFFER_BINDING: // now equivalent to GL_DRAW_FRAMEBUFFER_BINDING_ANGLE
case GL_DRAW_FRAMEBUFFER_BINDING_ANGLE: *params = mDrawFramebuffer->id(); break;
case GL_READ_FRAMEBUFFER_BINDING_ANGLE: *params = mReadFramebuffer->id(); break;
@@ -1219,11 +1447,34 @@ void State::getIntegerv(const gl::Data &data, GLenum pname, GLint *params)
case GL_CURRENT_PROGRAM: *params = mProgram ? mProgram->id() : 0; break;
case GL_PACK_ALIGNMENT: *params = mPack.alignment; break;
case GL_PACK_REVERSE_ROW_ORDER_ANGLE: *params = mPack.reverseRowOrder; break;
+ case GL_PACK_ROW_LENGTH:
+ *params = mPack.rowLength;
+ break;
+ case GL_PACK_SKIP_ROWS:
+ *params = mPack.skipRows;
+ break;
+ case GL_PACK_SKIP_PIXELS:
+ *params = mPack.skipPixels;
+ break;
case GL_UNPACK_ALIGNMENT: *params = mUnpack.alignment; break;
case GL_UNPACK_ROW_LENGTH: *params = mUnpack.rowLength; break;
+ case GL_UNPACK_IMAGE_HEIGHT:
+ *params = mUnpack.imageHeight;
+ break;
+ case GL_UNPACK_SKIP_IMAGES:
+ *params = mUnpack.skipImages;
+ break;
+ case GL_UNPACK_SKIP_ROWS:
+ *params = mUnpack.skipRows;
+ break;
+ case GL_UNPACK_SKIP_PIXELS:
+ *params = mUnpack.skipPixels;
+ break;
case GL_GENERATE_MIPMAP_HINT: *params = mGenerateMipmapHint; break;
case GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES: *params = mFragmentShaderDerivativeHint; break;
- case GL_ACTIVE_TEXTURE: *params = (mActiveSampler + GL_TEXTURE0); break;
+ case GL_ACTIVE_TEXTURE:
+ *params = (static_cast<GLint>(mActiveSampler) + GL_TEXTURE0);
+ break;
case GL_STENCIL_FUNC: *params = mDepthStencil.stencilFunc; break;
case GL_STENCIL_REF: *params = mStencilRef; break;
case GL_STENCIL_VALUE_MASK: *params = clampToInt(mDepthStencil.stencilMask); break;
@@ -1297,7 +1548,7 @@ void State::getIntegerv(const gl::Data &data, GLenum pname, GLint *params)
case GL_ALPHA_BITS:
{
gl::Framebuffer *framebuffer = getDrawFramebuffer();
- gl::FramebufferAttachment *colorbuffer = framebuffer->getFirstColorbuffer();
+ const gl::FramebufferAttachment *colorbuffer = framebuffer->getFirstColorbuffer();
if (colorbuffer)
{
@@ -1317,8 +1568,8 @@ void State::getIntegerv(const gl::Data &data, GLenum pname, GLint *params)
break;
case GL_DEPTH_BITS:
{
- gl::Framebuffer *framebuffer = getDrawFramebuffer();
- gl::FramebufferAttachment *depthbuffer = framebuffer->getDepthbuffer();
+ const gl::Framebuffer *framebuffer = getDrawFramebuffer();
+ const gl::FramebufferAttachment *depthbuffer = framebuffer->getDepthbuffer();
if (depthbuffer)
{
@@ -1332,8 +1583,8 @@ void State::getIntegerv(const gl::Data &data, GLenum pname, GLint *params)
break;
case GL_STENCIL_BITS:
{
- gl::Framebuffer *framebuffer = getDrawFramebuffer();
- gl::FramebufferAttachment *stencilbuffer = framebuffer->getStencilbuffer();
+ const gl::Framebuffer *framebuffer = getDrawFramebuffer();
+ const gl::FramebufferAttachment *stencilbuffer = framebuffer->getStencilbuffer();
if (stencilbuffer)
{
@@ -1347,25 +1598,30 @@ void State::getIntegerv(const gl::Data &data, GLenum pname, GLint *params)
break;
case GL_TEXTURE_BINDING_2D:
ASSERT(mActiveSampler < mMaxCombinedTextureImageUnits);
- *params = getSamplerTextureId(mActiveSampler, GL_TEXTURE_2D) ;
+ *params = getSamplerTextureId(static_cast<unsigned int>(mActiveSampler), GL_TEXTURE_2D);
break;
case GL_TEXTURE_BINDING_CUBE_MAP:
ASSERT(mActiveSampler < mMaxCombinedTextureImageUnits);
- *params = getSamplerTextureId(mActiveSampler, GL_TEXTURE_CUBE_MAP);
+ *params =
+ getSamplerTextureId(static_cast<unsigned int>(mActiveSampler), GL_TEXTURE_CUBE_MAP);
break;
case GL_TEXTURE_BINDING_3D:
ASSERT(mActiveSampler < mMaxCombinedTextureImageUnits);
- *params = getSamplerTextureId(mActiveSampler, GL_TEXTURE_3D);
+ *params = getSamplerTextureId(static_cast<unsigned int>(mActiveSampler), GL_TEXTURE_3D);
break;
case GL_TEXTURE_BINDING_2D_ARRAY:
ASSERT(mActiveSampler < mMaxCombinedTextureImageUnits);
- *params = getSamplerTextureId(mActiveSampler, GL_TEXTURE_2D_ARRAY);
+ *params =
+ getSamplerTextureId(static_cast<unsigned int>(mActiveSampler), GL_TEXTURE_2D_ARRAY);
break;
case GL_UNIFORM_BUFFER_BINDING:
*params = mGenericUniformBuffer.id();
break;
+ case GL_TRANSFORM_FEEDBACK_BINDING:
+ *params = mTransformFeedback.id();
+ break;
case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING:
- *params = mGenericTransformFeedbackBuffer.id();
+ *params = mTransformFeedback->getGenericBuffer().id();
break;
case GL_COPY_READ_BUFFER_BINDING:
*params = mCopyReadBuffer.id();
@@ -1379,20 +1635,45 @@ void State::getIntegerv(const gl::Data &data, GLenum pname, GLint *params)
case GL_PIXEL_UNPACK_BUFFER_BINDING:
*params = mUnpack.pixelBuffer.id();
break;
+ case GL_DEBUG_LOGGED_MESSAGES:
+ *params = static_cast<GLint>(mDebug.getMessageCount());
+ break;
+ case GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH:
+ *params = static_cast<GLint>(mDebug.getNextMessageLength());
+ break;
+ case GL_DEBUG_GROUP_STACK_DEPTH:
+ *params = static_cast<GLint>(mDebug.getGroupStackDepth());
+ break;
default:
UNREACHABLE();
break;
}
}
+void State::getPointerv(GLenum pname, void **params) const
+{
+ switch (pname)
+ {
+ case GL_DEBUG_CALLBACK_FUNCTION:
+ *params = reinterpret_cast<void *>(mDebug.getCallback());
+ break;
+ case GL_DEBUG_CALLBACK_USER_PARAM:
+ *params = const_cast<void *>(mDebug.getUserParam());
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+}
+
bool State::getIndexedIntegerv(GLenum target, GLuint index, GLint *data)
{
switch (target)
{
case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING:
- if (static_cast<size_t>(index) < mTransformFeedbackBuffers.size())
+ if (static_cast<size_t>(index) < mTransformFeedback->getIndexedBufferCount())
{
- *data = mTransformFeedbackBuffers[index].id();
+ *data = mTransformFeedback->getIndexedBuffer(index).id();
}
break;
case GL_UNIFORM_BUFFER_BINDING:
@@ -1413,15 +1694,15 @@ bool State::getIndexedInteger64v(GLenum target, GLuint index, GLint64 *data)
switch (target)
{
case GL_TRANSFORM_FEEDBACK_BUFFER_START:
- if (static_cast<size_t>(index) < mTransformFeedbackBuffers.size())
+ if (static_cast<size_t>(index) < mTransformFeedback->getIndexedBufferCount())
{
- *data = mTransformFeedbackBuffers[index].getOffset();
+ *data = mTransformFeedback->getIndexedBuffer(index).getOffset();
}
break;
case GL_TRANSFORM_FEEDBACK_BUFFER_SIZE:
- if (static_cast<size_t>(index) < mTransformFeedbackBuffers.size())
+ if (static_cast<size_t>(index) < mTransformFeedback->getIndexedBufferCount())
{
- *data = mTransformFeedbackBuffers[index].getSize();
+ *data = mTransformFeedback->getIndexedBuffer(index).getSize();
}
break;
case GL_UNIFORM_BUFFER_START:
@@ -1448,9 +1729,11 @@ bool State::hasMappedBuffer(GLenum target) const
if (target == GL_ARRAY_BUFFER)
{
const VertexArray *vao = getVertexArray();
- for (size_t attribIndex = 0; attribIndex < mVertexAttribCurrentValues.size(); attribIndex++)
+ const auto &vertexAttribs = vao->getVertexAttributes();
+ size_t maxEnabledAttrib = vao->getMaxEnabledAttribute();
+ for (size_t attribIndex = 0; attribIndex < maxEnabledAttrib; attribIndex++)
{
- const gl::VertexAttribute &vertexAttrib = vao->getVertexAttribute(attribIndex);
+ const gl::VertexAttribute &vertexAttrib = vertexAttribs[attribIndex];
gl::Buffer *boundBuffer = vertexAttrib.buffer.get();
if (vertexAttrib.enabled && boundBuffer && boundBuffer->isMapped())
{
@@ -1467,4 +1750,92 @@ bool State::hasMappedBuffer(GLenum target) const
}
}
+void State::syncDirtyObjects()
+{
+ if (!mDirtyObjects.any())
+ return;
+
+ syncDirtyObjects(mDirtyObjects);
+}
+
+void State::syncDirtyObjects(const DirtyObjects &bitset)
+{
+ for (auto dirtyObject : angle::IterateBitSet(bitset))
+ {
+ switch (dirtyObject)
+ {
+ case DIRTY_OBJECT_READ_FRAMEBUFFER:
+ ASSERT(mReadFramebuffer);
+ mReadFramebuffer->syncState();
+ break;
+ case DIRTY_OBJECT_DRAW_FRAMEBUFFER:
+ ASSERT(mDrawFramebuffer);
+ mDrawFramebuffer->syncState();
+ break;
+ case DIRTY_OBJECT_VERTEX_ARRAY:
+ ASSERT(mVertexArray);
+ mVertexArray->syncImplState();
+ break;
+ case DIRTY_OBJECT_PROGRAM:
+ // TODO(jmadill): implement this
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+ }
+
+ mDirtyObjects &= ~bitset;
+}
+
+void State::syncDirtyObject(GLenum target)
+{
+ DirtyObjects localSet;
+
+ switch (target)
+ {
+ case GL_READ_FRAMEBUFFER:
+ localSet.set(DIRTY_OBJECT_READ_FRAMEBUFFER);
+ break;
+ case GL_DRAW_FRAMEBUFFER:
+ localSet.set(DIRTY_OBJECT_DRAW_FRAMEBUFFER);
+ break;
+ case GL_FRAMEBUFFER:
+ localSet.set(DIRTY_OBJECT_READ_FRAMEBUFFER);
+ localSet.set(DIRTY_OBJECT_DRAW_FRAMEBUFFER);
+ break;
+ case GL_VERTEX_ARRAY:
+ localSet.set(DIRTY_OBJECT_VERTEX_ARRAY);
+ break;
+ case GL_PROGRAM:
+ localSet.set(DIRTY_OBJECT_PROGRAM);
+ break;
+ }
+
+ syncDirtyObjects(localSet);
}
+
+void State::setObjectDirty(GLenum target)
+{
+ switch (target)
+ {
+ case GL_READ_FRAMEBUFFER:
+ mDirtyObjects.set(DIRTY_OBJECT_READ_FRAMEBUFFER);
+ break;
+ case GL_DRAW_FRAMEBUFFER:
+ mDirtyObjects.set(DIRTY_OBJECT_DRAW_FRAMEBUFFER);
+ break;
+ case GL_FRAMEBUFFER:
+ mDirtyObjects.set(DIRTY_OBJECT_READ_FRAMEBUFFER);
+ mDirtyObjects.set(DIRTY_OBJECT_DRAW_FRAMEBUFFER);
+ break;
+ case GL_VERTEX_ARRAY:
+ mDirtyObjects.set(DIRTY_OBJECT_VERTEX_ARRAY);
+ break;
+ case GL_PROGRAM:
+ mDirtyObjects.set(DIRTY_OBJECT_PROGRAM);
+ break;
+ }
+}
+
+} // namespace gl
diff --git a/src/3rdparty/angle/src/libANGLE/State.h b/src/3rdparty/angle/src/libANGLE/State.h
index 4370a2f16f..e822d7e679 100644
--- a/src/3rdparty/angle/src/libANGLE/State.h
+++ b/src/3rdparty/angle/src/libANGLE/State.h
@@ -9,15 +9,19 @@
#ifndef LIBANGLE_STATE_H_
#define LIBANGLE_STATE_H_
+#include <bitset>
+#include <memory>
+
#include "common/angleutils.h"
+#include "libANGLE/Debug.h"
+#include "libANGLE/Program.h"
#include "libANGLE/RefCountObject.h"
-#include "libANGLE/angletypes.h"
-#include "libANGLE/VertexAttribute.h"
#include "libANGLE/Renderbuffer.h"
+#include "libANGLE/Sampler.h"
#include "libANGLE/Texture.h"
#include "libANGLE/TransformFeedback.h"
-#include "libANGLE/Program.h"
-#include "libANGLE/Sampler.h"
+#include "libANGLE/VertexAttribute.h"
+#include "libANGLE/angletypes.h"
namespace gl
{
@@ -27,7 +31,7 @@ class Context;
struct Caps;
struct Data;
-typedef std::map< GLenum, BindingPointer<Texture> > TextureMap;
+typedef std::map<GLenum, BindingPointer<Texture>> TextureMap;
class State : angle::NonCopyable
{
@@ -35,7 +39,10 @@ class State : angle::NonCopyable
State();
~State();
- void initialize(const Caps& caps, GLuint clientVersion);
+ void initialize(const Caps &caps,
+ const Extensions &extensions,
+ GLuint clientVersion,
+ bool debug);
void reset();
// State chunk getters
@@ -75,7 +82,8 @@ class State : angle::NonCopyable
void setDepthTest(bool enabled);
void setDepthFunc(GLenum depthFunc);
void setDepthRange(float zNear, float zFar);
- void getDepthRange(float *zNear, float *zFar) const;
+ float getNearPlane() const;
+ float getFarPlane() const;
// Blend state manipulation
bool isBlendEnabled() const;
@@ -108,7 +116,8 @@ class State : angle::NonCopyable
bool isSampleCoverageEnabled() const;
void setSampleCoverage(bool enabled);
void setSampleCoverageParams(GLclampf value, bool invert);
- void getSampleCoverageParams(GLclampf *value, bool *invert) const;
+ GLclampf getSampleCoverageValue() const;
+ bool getSampleCoverageInvert() const;
// Scissor test state toggle & query
bool isScissorTestEnabled() const;
@@ -126,6 +135,7 @@ class State : angle::NonCopyable
// Line width state setter
void setLineWidth(GLfloat width);
+ float getLineWidth() const;
// Hint setters
void setGenerateMipmapHint(GLenum hint);
@@ -139,6 +149,7 @@ class State : angle::NonCopyable
void setActiveSampler(unsigned int active);
unsigned int getActiveSampler() const;
void setSamplerTexture(GLenum type, Texture *texture);
+ Texture *getTargetTexture(GLenum target) const;
Texture *getSamplerTexture(unsigned int sampler, GLenum type) const;
GLuint getSamplerTextureId(unsigned int sampler, GLenum type) const;
void detachTexture(const TextureMap &zeroTextures, GLuint texture);
@@ -185,6 +196,7 @@ class State : angle::NonCopyable
// Query binding manipulation
bool isQueryActive() const;
+ bool isQueryActive(Query *query) const;
void setActiveQuery(GLenum target, Query *query);
GLuint getActiveQueryId(GLenum target) const;
Query *getActiveQuery(GLenum target) const;
@@ -193,23 +205,11 @@ class State : angle::NonCopyable
// GL_ARRAY_BUFFER
void setArrayBufferBinding(Buffer *buffer);
GLuint getArrayBufferId() const;
- bool removeArrayBufferBinding(GLuint buffer);
// GL_UNIFORM_BUFFER - Both indexed and generic targets
void setGenericUniformBufferBinding(Buffer *buffer);
void setIndexedUniformBufferBinding(GLuint index, Buffer *buffer, GLintptr offset, GLsizeiptr size);
- GLuint getIndexedUniformBufferId(GLuint index) const;
- Buffer *getIndexedUniformBuffer(GLuint index) const;
- GLintptr getIndexedUniformBufferOffset(GLuint index) const;
- GLsizeiptr getIndexedUniformBufferSize(GLuint index) const;
-
- // GL_TRANSFORM_FEEDBACK_BUFFER - Both indexed and generic targets
- void setGenericTransformFeedbackBufferBinding(Buffer *buffer);
- void setIndexedTransformFeedbackBufferBinding(GLuint index, Buffer *buffer, GLintptr offset, GLsizeiptr size);
- GLuint getIndexedTransformFeedbackBufferId(GLuint index) const;
- Buffer *getIndexedTransformFeedbackBuffer(GLuint index) const;
- GLuint getIndexedTransformFeedbackBufferOffset(GLuint index) const;
- size_t getTransformFeedbackBufferIndexRange() const;
+ const OffsetBindingPointer<Buffer> &getIndexedUniformBuffer(size_t index) const;
// GL_COPY_[READ/WRITE]_BUFFER
void setCopyReadBufferBinding(Buffer *buffer);
@@ -221,6 +221,8 @@ class State : angle::NonCopyable
// Retrieve typed buffer by target (non-indexed)
Buffer *getTargetBuffer(GLenum target) const;
+ // Detach a buffer from all bindings
+ void detachBuffer(GLuint bufferName);
// Vertex attrib manipulation
void setEnableVertexAttribArray(unsigned int attribNum, bool enabled);
@@ -229,6 +231,7 @@ class State : angle::NonCopyable
void setVertexAttribi(GLuint index, const GLint values[4]);
void setVertexAttribState(unsigned int attribNum, Buffer *boundBuffer, GLint size, GLenum type,
bool normalized, bool pureInteger, GLsizei stride, const void *pointer);
+ void setVertexAttribDivisor(GLuint index, GLuint divisor);
const VertexAttribCurrentValueData &getVertexAttribCurrentValue(unsigned int attribNum) const;
const void *getVertexAttribPointer(unsigned int attribNum) const;
@@ -237,6 +240,12 @@ class State : angle::NonCopyable
GLint getPackAlignment() const;
void setPackReverseRowOrder(bool reverseRowOrder);
bool getPackReverseRowOrder() const;
+ void setPackRowLength(GLint rowLength);
+ GLint getPackRowLength() const;
+ void setPackSkipRows(GLint skipRows);
+ GLint getPackSkipRows() const;
+ void setPackSkipPixels(GLint skipPixels);
+ GLint getPackSkipPixels() const;
const PixelPackState &getPackState() const;
PixelPackState &getPackState();
@@ -245,18 +254,122 @@ class State : angle::NonCopyable
GLint getUnpackAlignment() const;
void setUnpackRowLength(GLint rowLength);
GLint getUnpackRowLength() const;
+ void setUnpackImageHeight(GLint imageHeight);
+ GLint getUnpackImageHeight() const;
+ void setUnpackSkipImages(GLint skipImages);
+ GLint getUnpackSkipImages() const;
+ void setUnpackSkipRows(GLint skipRows);
+ GLint getUnpackSkipRows() const;
+ void setUnpackSkipPixels(GLint skipPixels);
+ GLint getUnpackSkipPixels() const;
const PixelUnpackState &getUnpackState() const;
PixelUnpackState &getUnpackState();
+ // Debug state
+ const Debug &getDebug() const;
+ Debug &getDebug();
+
// State query functions
void getBooleanv(GLenum pname, GLboolean *params);
void getFloatv(GLenum pname, GLfloat *params);
void getIntegerv(const gl::Data &data, GLenum pname, GLint *params);
+ void getPointerv(GLenum pname, void **params) const;
bool getIndexedIntegerv(GLenum target, GLuint index, GLint *data);
bool getIndexedInteger64v(GLenum target, GLuint index, GLint64 *data);
bool hasMappedBuffer(GLenum target) const;
+ enum DirtyBitType
+ {
+ DIRTY_BIT_SCISSOR_TEST_ENABLED,
+ DIRTY_BIT_SCISSOR,
+ DIRTY_BIT_VIEWPORT,
+ DIRTY_BIT_DEPTH_RANGE,
+ DIRTY_BIT_BLEND_ENABLED,
+ DIRTY_BIT_BLEND_COLOR,
+ DIRTY_BIT_BLEND_FUNCS,
+ DIRTY_BIT_BLEND_EQUATIONS,
+ DIRTY_BIT_COLOR_MASK,
+ DIRTY_BIT_SAMPLE_ALPHA_TO_COVERAGE_ENABLED,
+ DIRTY_BIT_SAMPLE_COVERAGE_ENABLED,
+ DIRTY_BIT_SAMPLE_COVERAGE,
+ DIRTY_BIT_DEPTH_TEST_ENABLED,
+ DIRTY_BIT_DEPTH_FUNC,
+ DIRTY_BIT_DEPTH_MASK,
+ DIRTY_BIT_STENCIL_TEST_ENABLED,
+ DIRTY_BIT_STENCIL_FUNCS_FRONT,
+ DIRTY_BIT_STENCIL_FUNCS_BACK,
+ DIRTY_BIT_STENCIL_OPS_FRONT,
+ DIRTY_BIT_STENCIL_OPS_BACK,
+ DIRTY_BIT_STENCIL_WRITEMASK_FRONT,
+ DIRTY_BIT_STENCIL_WRITEMASK_BACK,
+ DIRTY_BIT_CULL_FACE_ENABLED,
+ DIRTY_BIT_CULL_FACE,
+ DIRTY_BIT_FRONT_FACE,
+ DIRTY_BIT_POLYGON_OFFSET_FILL_ENABLED,
+ DIRTY_BIT_POLYGON_OFFSET,
+ DIRTY_BIT_RASTERIZER_DISCARD_ENABLED,
+ DIRTY_BIT_LINE_WIDTH,
+ DIRTY_BIT_PRIMITIVE_RESTART_ENABLED,
+ DIRTY_BIT_CLEAR_COLOR,
+ DIRTY_BIT_CLEAR_DEPTH,
+ DIRTY_BIT_CLEAR_STENCIL,
+ DIRTY_BIT_UNPACK_ALIGNMENT,
+ DIRTY_BIT_UNPACK_ROW_LENGTH,
+ DIRTY_BIT_UNPACK_IMAGE_HEIGHT,
+ DIRTY_BIT_UNPACK_SKIP_IMAGES,
+ DIRTY_BIT_UNPACK_SKIP_ROWS,
+ DIRTY_BIT_UNPACK_SKIP_PIXELS,
+ DIRTY_BIT_PACK_ALIGNMENT,
+ DIRTY_BIT_PACK_REVERSE_ROW_ORDER,
+ DIRTY_BIT_PACK_ROW_LENGTH,
+ DIRTY_BIT_PACK_SKIP_ROWS,
+ DIRTY_BIT_PACK_SKIP_PIXELS,
+ DIRTY_BIT_DITHER_ENABLED,
+ DIRTY_BIT_GENERATE_MIPMAP_HINT,
+ DIRTY_BIT_SHADER_DERIVATIVE_HINT,
+ DIRTY_BIT_READ_FRAMEBUFFER_BINDING,
+ DIRTY_BIT_DRAW_FRAMEBUFFER_BINDING,
+ DIRTY_BIT_RENDERBUFFER_BINDING,
+ DIRTY_BIT_VERTEX_ARRAY_BINDING,
+ DIRTY_BIT_PROGRAM_BINDING,
+ DIRTY_BIT_CURRENT_VALUE_0,
+ DIRTY_BIT_CURRENT_VALUE_MAX = DIRTY_BIT_CURRENT_VALUE_0 + MAX_VERTEX_ATTRIBS,
+ DIRTY_BIT_INVALID = DIRTY_BIT_CURRENT_VALUE_MAX,
+ DIRTY_BIT_MAX = DIRTY_BIT_INVALID,
+ };
+
+ // TODO(jmadill): Consider storing dirty objects in a list instead of by binding.
+ enum DirtyObjectType
+ {
+ DIRTY_OBJECT_READ_FRAMEBUFFER,
+ DIRTY_OBJECT_DRAW_FRAMEBUFFER,
+ DIRTY_OBJECT_VERTEX_ARRAY,
+ DIRTY_OBJECT_PROGRAM,
+ DIRTY_OBJECT_UNKNOWN,
+ DIRTY_OBJECT_MAX = DIRTY_OBJECT_UNKNOWN,
+ };
+
+ typedef std::bitset<DIRTY_BIT_MAX> DirtyBits;
+ const DirtyBits &getDirtyBits() const { return mDirtyBits; }
+ void clearDirtyBits() { mDirtyBits.reset(); }
+ void clearDirtyBits(const DirtyBits &bitset) { mDirtyBits &= ~bitset; }
+ void setAllDirtyBits() { mDirtyBits.set(); }
+
+ typedef std::bitset<DIRTY_OBJECT_MAX> DirtyObjects;
+ void clearDirtyObjects() { mDirtyObjects.reset(); }
+ void setAllDirtyObjects() { mDirtyObjects.set(); }
+ void syncDirtyObjects();
+ void syncDirtyObjects(const DirtyObjects &bitset);
+ void syncDirtyObject(GLenum target);
+ void setObjectDirty(GLenum target);
+
+ // Dirty bit masks
+ const DirtyBits &unpackStateBitMask() const { return mUnpackStateBitMask; }
+ const DirtyBits &packStateBitMask() const { return mPackStateBitMask; }
+ const DirtyBits &clearStateBitMask() const { return mClearStateBitMask; }
+ const DirtyBits &blitStateBitMask() const { return mBlitStateBitMask; }
+
private:
// Cached values from Context's caps
GLuint mMaxDrawBuffers;
@@ -302,23 +415,21 @@ class State : angle::NonCopyable
// Texture and sampler bindings
size_t mActiveSampler; // Active texture unit selector - GL_TEXTURE0
- typedef std::vector< BindingPointer<Texture> > TextureBindingVector;
+ typedef std::vector<BindingPointer<Texture>> TextureBindingVector;
typedef std::map<GLenum, TextureBindingVector> TextureBindingMap;
TextureBindingMap mSamplerTextures;
- typedef std::vector< BindingPointer<Sampler> > SamplerBindingVector;
+ typedef std::vector<BindingPointer<Sampler>> SamplerBindingVector;
SamplerBindingVector mSamplers;
- typedef std::map< GLenum, BindingPointer<Query> > ActiveQueryMap;
+ typedef std::map<GLenum, BindingPointer<Query>> ActiveQueryMap;
ActiveQueryMap mActiveQueries;
BindingPointer<Buffer> mGenericUniformBuffer;
- typedef std::vector< OffsetBindingPointer<Buffer> > BufferVector;
+ typedef std::vector<OffsetBindingPointer<Buffer>> BufferVector;
BufferVector mUniformBuffers;
BindingPointer<TransformFeedback> mTransformFeedback;
- BindingPointer<Buffer> mGenericTransformFeedbackBuffer;
- BufferVector mTransformFeedbackBuffers;
BindingPointer<Buffer> mCopyReadBuffer;
BindingPointer<Buffer> mCopyWriteBuffer;
@@ -327,6 +438,16 @@ class State : angle::NonCopyable
PixelPackState mPack;
bool mPrimitiveRestart;
+
+ Debug mDebug;
+
+ DirtyBits mDirtyBits;
+ DirtyBits mUnpackStateBitMask;
+ DirtyBits mPackStateBitMask;
+ DirtyBits mClearStateBitMask;
+ DirtyBits mBlitStateBitMask;
+
+ DirtyObjects mDirtyObjects;
};
}
diff --git a/src/3rdparty/angle/src/libANGLE/Surface.cpp b/src/3rdparty/angle/src/libANGLE/Surface.cpp
index ac455f3905..b5ed0ff5a6 100644
--- a/src/3rdparty/angle/src/libANGLE/Surface.cpp
+++ b/src/3rdparty/angle/src/libANGLE/Surface.cpp
@@ -11,17 +11,25 @@
#include "libANGLE/Surface.h"
#include "libANGLE/Config.h"
+#include "libANGLE/Framebuffer.h"
#include "libANGLE/Texture.h"
-#include "libANGLE/renderer/SurfaceImpl.h"
#include <EGL/eglext.h>
+#include <iostream>
+
namespace egl
{
-Surface::Surface(rx::SurfaceImpl *impl, EGLint surfaceType, const egl::Config *config, const AttributeMap &attributes)
- : RefCountObject(0), // id unused
+Surface::Surface(rx::SurfaceImpl *impl,
+ EGLint surfaceType,
+ const egl::Config *config,
+ const AttributeMap &attributes)
+ : FramebufferAttachmentObject(),
mImplementation(impl),
+ mDefaultFramebuffer(nullptr),
+ mCurrentCount(0),
+ mDestroyed(false),
mType(surfaceType),
mConfig(config),
mPostSubBufferRequested(false),
@@ -33,12 +41,15 @@ Surface::Surface(rx::SurfaceImpl *impl, EGLint surfaceType, const egl::Config *c
// FIXME: Determine actual pixel aspect ratio
mPixelAspectRatio(static_cast<EGLint>(1.0 * EGL_DISPLAY_SCALING)),
mRenderBuffer(EGL_BACK_BUFFER),
- mSwapBehavior(EGL_BUFFER_PRESERVED),
- mTexture(NULL)
+ mSwapBehavior(impl->getSwapBehavior()),
+ mOrientation(0),
+ mTexture()
{
- addRef();
-
mPostSubBufferRequested = (attributes.get(EGL_POST_SUB_BUFFER_SUPPORTED_NV, EGL_FALSE) == EGL_TRUE);
+ mFlexibleSurfaceCompatibilityRequested =
+ (attributes.get(EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE, EGL_FALSE) == EGL_TRUE);
+
+ mDirectComposition = (attributes.get(EGL_DIRECT_COMPOSITION_ANGLE, EGL_FALSE) == EGL_TRUE);
mFixedSize = (attributes.get(EGL_FIXED_SIZE_ANGLE, EGL_FALSE) == EGL_TRUE);
if (mFixedSize)
@@ -52,23 +63,55 @@ Surface::Surface(rx::SurfaceImpl *impl, EGLint surfaceType, const egl::Config *c
mTextureFormat = attributes.get(EGL_TEXTURE_FORMAT, EGL_NO_TEXTURE);
mTextureTarget = attributes.get(EGL_TEXTURE_TARGET, EGL_NO_TEXTURE);
}
+
+ mOrientation = attributes.get(EGL_SURFACE_ORIENTATION_ANGLE, 0);
+
+ mDefaultFramebuffer = createDefaultFramebuffer();
+ ASSERT(mDefaultFramebuffer != nullptr);
}
Surface::~Surface()
{
- if (mTexture)
+ if (mTexture.get())
{
if (mImplementation)
{
- mImplementation->releaseTexImage(mTexture->id());
+ mImplementation->releaseTexImage(EGL_BACK_BUFFER);
}
- mTexture->releaseTexImage();
- mTexture = NULL;
+ mTexture->releaseTexImageFromSurface();
+ mTexture.set(nullptr);
}
+ SafeDelete(mDefaultFramebuffer);
SafeDelete(mImplementation);
}
+void Surface::setIsCurrent(bool isCurrent)
+{
+ if (isCurrent)
+ {
+ mCurrentCount++;
+ }
+ else
+ {
+ ASSERT(mCurrentCount > 0);
+ mCurrentCount--;
+ if (mCurrentCount == 0 && mDestroyed)
+ {
+ delete this;
+ }
+ }
+}
+
+void Surface::onDestroy()
+{
+ mDestroyed = true;
+ if (mCurrentCount == 0)
+ {
+ delete this;
+ }
+}
+
EGLint Surface::getType() const
{
return mType;
@@ -136,31 +179,83 @@ EGLint Surface::isFixedSize() const
EGLint Surface::getWidth() const
{
- return mFixedSize ? mFixedWidth : mImplementation->getWidth();
+ return mFixedSize ? static_cast<EGLint>(mFixedWidth) : mImplementation->getWidth();
}
EGLint Surface::getHeight() const
{
- return mFixedSize ? mFixedHeight : mImplementation->getHeight();
+ return mFixedSize ? static_cast<EGLint>(mFixedHeight) : mImplementation->getHeight();
}
Error Surface::bindTexImage(gl::Texture *texture, EGLint buffer)
{
- ASSERT(!mTexture);
+ ASSERT(!mTexture.get());
- texture->bindTexImage(this);
- mTexture = texture;
- return mImplementation->bindTexImage(buffer);
+ texture->bindTexImageFromSurface(this);
+ mTexture.set(texture);
+ return mImplementation->bindTexImage(texture, buffer);
}
Error Surface::releaseTexImage(EGLint buffer)
{
- ASSERT(mTexture);
- gl::Texture *boundTexture = mTexture;
- mTexture = NULL;
+ ASSERT(mTexture.get());
+ mTexture->releaseTexImageFromSurface();
+ mTexture.set(nullptr);
- boundTexture->releaseTexImage();
return mImplementation->releaseTexImage(buffer);
}
+void Surface::releaseTexImageFromTexture()
+{
+ ASSERT(mTexture.get());
+ mTexture.set(nullptr);
+}
+
+gl::Extents Surface::getAttachmentSize(const gl::FramebufferAttachment::Target & /*target*/) const
+{
+ return gl::Extents(getWidth(), getHeight(), 1);
+}
+
+GLenum Surface::getAttachmentInternalFormat(const gl::FramebufferAttachment::Target &target) const
+{
+ const egl::Config *config = getConfig();
+ return (target.binding() == GL_BACK ? config->renderTargetFormat : config->depthStencilFormat);
+}
+
+GLsizei Surface::getAttachmentSamples(const gl::FramebufferAttachment::Target &target) const
+{
+ return getConfig()->samples;
+}
+
+GLuint Surface::getId() const
+{
+ UNREACHABLE();
+ return 0;
+}
+
+gl::Framebuffer *Surface::createDefaultFramebuffer()
+{
+ gl::Framebuffer *framebuffer = new gl::Framebuffer(mImplementation);
+
+ GLenum drawBufferState = GL_BACK;
+ framebuffer->setDrawBuffers(1, &drawBufferState);
+ framebuffer->setReadBuffer(GL_BACK);
+
+ framebuffer->setAttachment(GL_FRAMEBUFFER_DEFAULT, GL_BACK, gl::ImageIndex::MakeInvalid(),
+ this);
+
+ if (mConfig->depthSize > 0)
+ {
+ framebuffer->setAttachment(GL_FRAMEBUFFER_DEFAULT, GL_DEPTH, gl::ImageIndex::MakeInvalid(),
+ this);
+ }
+
+ if (mConfig->stencilSize > 0)
+ {
+ framebuffer->setAttachment(GL_FRAMEBUFFER_DEFAULT, GL_STENCIL,
+ gl::ImageIndex::MakeInvalid(), this);
+ }
+
+ return framebuffer;
+}
}
diff --git a/src/3rdparty/angle/src/libANGLE/Surface.h b/src/3rdparty/angle/src/libANGLE/Surface.h
index 430bf0195d..e110f5da7b 100644
--- a/src/3rdparty/angle/src/libANGLE/Surface.h
+++ b/src/3rdparty/angle/src/libANGLE/Surface.h
@@ -15,25 +15,23 @@
#include "common/angleutils.h"
#include "libANGLE/Error.h"
+#include "libANGLE/FramebufferAttachment.h"
#include "libANGLE/RefCountObject.h"
+#include "libANGLE/renderer/SurfaceImpl.h"
namespace gl
{
+class Framebuffer;
class Texture;
}
-namespace rx
-{
-class SurfaceImpl;
-}
-
namespace egl
{
class AttributeMap;
class Display;
struct Config;
-class Surface final : public RefCountObject
+class Surface final : public gl::FramebufferAttachmentObject
{
public:
Surface(rx::SurfaceImpl *impl, EGLint surfaceType, const egl::Config *config, const AttributeMap &attributes);
@@ -52,6 +50,8 @@ class Surface final : public RefCountObject
EGLint isPostSubBufferSupported() const;
void setSwapInterval(EGLint interval);
+ void setIsCurrent(bool isCurrent);
+ void onDestroy();
const Config *getConfig() const;
@@ -64,25 +64,56 @@ class Surface final : public RefCountObject
EGLenum getTextureFormat() const;
EGLenum getTextureTarget() const;
- gl::Texture *getBoundTexture() const { return mTexture; }
+ gl::Texture *getBoundTexture() const { return mTexture.get(); }
+ gl::Framebuffer *getDefaultFramebuffer() { return mDefaultFramebuffer; }
EGLint isFixedSize() const;
+ // FramebufferAttachmentObject implementation
+ gl::Extents getAttachmentSize(const gl::FramebufferAttachment::Target &target) const override;
+ GLenum getAttachmentInternalFormat(const gl::FramebufferAttachment::Target &target) const override;
+ GLsizei getAttachmentSamples(const gl::FramebufferAttachment::Target &target) const override;
+
+ void onAttach() override {}
+ void onDetach() override {}
+ GLuint getId() const override;
+
+ bool flexibleSurfaceCompatibilityRequested() const
+ {
+ return mFlexibleSurfaceCompatibilityRequested;
+ }
+ EGLint getOrientation() const { return mOrientation; }
+
+ bool directComposition() const { return mDirectComposition; }
+
private:
virtual ~Surface();
+ rx::FramebufferAttachmentObjectImpl *getAttachmentImpl() const override { return mImplementation; }
+
+ gl::Framebuffer *createDefaultFramebuffer();
+
+ // ANGLE-only method, used internally
+ friend class gl::Texture;
+ void releaseTexImageFromTexture();
rx::SurfaceImpl *mImplementation;
+ gl::Framebuffer *mDefaultFramebuffer;
+ int mCurrentCount;
+ bool mDestroyed;
EGLint mType;
const egl::Config *mConfig;
bool mPostSubBufferRequested;
+ bool mFlexibleSurfaceCompatibilityRequested;
bool mFixedSize;
size_t mFixedWidth;
size_t mFixedHeight;
+ bool mDirectComposition;
+
EGLenum mTextureFormat;
EGLenum mTextureTarget;
@@ -90,7 +121,9 @@ class Surface final : public RefCountObject
EGLenum mRenderBuffer; // Render buffer
EGLenum mSwapBehavior; // Buffer swap behavior
- gl::Texture *mTexture;
+ EGLint mOrientation;
+
+ BindingPointer<gl::Texture> mTexture;
};
}
diff --git a/src/3rdparty/angle/src/libANGLE/Texture.cpp b/src/3rdparty/angle/src/libANGLE/Texture.cpp
index cd4584f694..5ef6762d3d 100644
--- a/src/3rdparty/angle/src/libANGLE/Texture.cpp
+++ b/src/3rdparty/angle/src/libANGLE/Texture.cpp
@@ -7,14 +7,15 @@
// Texture.cpp: Implements the gl::Texture class. [OpenGL ES 2.0.24] section 3.7 page 63.
#include "libANGLE/Texture.h"
-#include "libANGLE/Data.h"
-#include "libANGLE/formatutils.h"
-
-#include "libANGLE/Config.h"
-#include "libANGLE/Surface.h"
#include "common/mathutil.h"
#include "common/utilities.h"
+#include "libANGLE/Config.h"
+#include "libANGLE/Context.h"
+#include "libANGLE/Data.h"
+#include "libANGLE/Image.h"
+#include "libANGLE/Surface.h"
+#include "libANGLE/formatutils.h"
namespace gl
{
@@ -46,14 +47,11 @@ static size_t GetImageDescIndex(GLenum target, size_t level)
return IsCubeMapTextureTarget(target) ? ((level * 6) + CubeMapTextureTargetToLayerIndex(target)) : level;
}
-unsigned int Texture::mCurrentTextureSerial = 1;
-
Texture::Texture(rx::TextureImpl *impl, GLuint id, GLenum target)
- : RefCountObject(id),
+ : egl::ImageSibling(id),
mTexture(impl),
- mTextureSerial(issueTextureSerial()),
- mUsage(GL_NONE),
- mImmutableLevelCount(0),
+ mLabel(),
+ mTextureState(),
mTarget(target),
mImageDescs(IMPLEMENTATION_MAX_TEXTURE_LEVELS * (target == GL_TEXTURE_CUBE_MAP ? 6 : 1)),
mCompletenessCache(),
@@ -71,20 +69,210 @@ Texture::~Texture()
SafeDelete(mTexture);
}
+void Texture::setLabel(const std::string &label)
+{
+ mLabel = label;
+}
+
+const std::string &Texture::getLabel() const
+{
+ return mLabel;
+}
+
GLenum Texture::getTarget() const
{
return mTarget;
}
+void Texture::setSwizzleRed(GLenum swizzleRed)
+{
+ mTextureState.swizzleRed = swizzleRed;
+}
+
+GLenum Texture::getSwizzleRed() const
+{
+ return mTextureState.swizzleRed;
+}
+
+void Texture::setSwizzleGreen(GLenum swizzleGreen)
+{
+ mTextureState.swizzleGreen = swizzleGreen;
+}
+
+GLenum Texture::getSwizzleGreen() const
+{
+ return mTextureState.swizzleGreen;
+}
+
+void Texture::setSwizzleBlue(GLenum swizzleBlue)
+{
+ mTextureState.swizzleBlue = swizzleBlue;
+}
+
+GLenum Texture::getSwizzleBlue() const
+{
+ return mTextureState.swizzleBlue;
+}
+
+void Texture::setSwizzleAlpha(GLenum swizzleAlpha)
+{
+ mTextureState.swizzleAlpha = swizzleAlpha;
+}
+
+GLenum Texture::getSwizzleAlpha() const
+{
+ return mTextureState.swizzleAlpha;
+}
+
+void Texture::setMinFilter(GLenum minFilter)
+{
+ mTextureState.samplerState.minFilter = minFilter;
+}
+
+GLenum Texture::getMinFilter() const
+{
+ return mTextureState.samplerState.minFilter;
+}
+
+void Texture::setMagFilter(GLenum magFilter)
+{
+ mTextureState.samplerState.magFilter = magFilter;
+}
+
+GLenum Texture::getMagFilter() const
+{
+ return mTextureState.samplerState.magFilter;
+}
+
+void Texture::setWrapS(GLenum wrapS)
+{
+ mTextureState.samplerState.wrapS = wrapS;
+}
+
+GLenum Texture::getWrapS() const
+{
+ return mTextureState.samplerState.wrapS;
+}
+
+void Texture::setWrapT(GLenum wrapT)
+{
+ mTextureState.samplerState.wrapT = wrapT;
+}
+
+GLenum Texture::getWrapT() const
+{
+ return mTextureState.samplerState.wrapT;
+}
+
+void Texture::setWrapR(GLenum wrapR)
+{
+ mTextureState.samplerState.wrapR = wrapR;
+}
+
+GLenum Texture::getWrapR() const
+{
+ return mTextureState.samplerState.wrapR;
+}
+
+void Texture::setMaxAnisotropy(float maxAnisotropy)
+{
+ mTextureState.samplerState.maxAnisotropy = maxAnisotropy;
+}
+
+float Texture::getMaxAnisotropy() const
+{
+ return mTextureState.samplerState.maxAnisotropy;
+}
+
+void Texture::setMinLod(GLfloat minLod)
+{
+ mTextureState.samplerState.minLod = minLod;
+}
+
+GLfloat Texture::getMinLod() const
+{
+ return mTextureState.samplerState.minLod;
+}
+
+void Texture::setMaxLod(GLfloat maxLod)
+{
+ mTextureState.samplerState.maxLod = maxLod;
+}
+
+GLfloat Texture::getMaxLod() const
+{
+ return mTextureState.samplerState.maxLod;
+}
+
+void Texture::setCompareMode(GLenum compareMode)
+{
+ mTextureState.samplerState.compareMode = compareMode;
+}
+
+GLenum Texture::getCompareMode() const
+{
+ return mTextureState.samplerState.compareMode;
+}
+
+void Texture::setCompareFunc(GLenum compareFunc)
+{
+ mTextureState.samplerState.compareFunc = compareFunc;
+}
+
+GLenum Texture::getCompareFunc() const
+{
+ return mTextureState.samplerState.compareFunc;
+}
+
+const SamplerState &Texture::getSamplerState() const
+{
+ return mTextureState.samplerState;
+}
+
+void Texture::setBaseLevel(GLuint baseLevel)
+{
+ mTextureState.baseLevel = baseLevel;
+}
+
+GLuint Texture::getBaseLevel() const
+{
+ return mTextureState.baseLevel;
+}
+
+void Texture::setMaxLevel(GLuint maxLevel)
+{
+ mTextureState.maxLevel = maxLevel;
+}
+
+GLuint Texture::getMaxLevel() const
+{
+ return mTextureState.maxLevel;
+}
+
+bool Texture::getImmutableFormat() const
+{
+ return mTextureState.immutableFormat;
+}
+
+GLuint Texture::getImmutableLevels() const
+{
+ return mTextureState.immutableLevels;
+}
+
void Texture::setUsage(GLenum usage)
{
- mUsage = usage;
+ mTextureState.usage = usage;
getImplementation()->setUsage(usage);
}
GLenum Texture::getUsage() const
{
- return mUsage;
+ return mTextureState.usage;
+}
+
+const TextureState &Texture::getTextureState() const
+{
+ return mTextureState;
}
size_t Texture::getWidth(GLenum target, size_t level) const
@@ -113,7 +301,7 @@ GLenum Texture::getInternalFormat(GLenum target, size_t level) const
bool Texture::isSamplerComplete(const SamplerState &samplerState, const Data &data) const
{
- const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), samplerState.baseLevel);
+ const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), mTextureState.baseLevel);
const TextureCaps &textureCaps = data.textureCaps->get(baseImageDesc.internalFormat);
if (!mCompletenessCache.cacheValid ||
mCompletenessCache.samplerState != samplerState ||
@@ -131,6 +319,11 @@ bool Texture::isSamplerComplete(const SamplerState &samplerState, const Data &da
return mCompletenessCache.samplerComplete;
}
+bool Texture::isMipmapComplete() const
+{
+ return computeMipmapCompleteness();
+}
+
// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
bool Texture::isCubeComplete() const
{
@@ -156,76 +349,122 @@ bool Texture::isCubeComplete() const
return true;
}
-unsigned int Texture::getTextureSerial() const
+size_t Texture::getMipCompleteLevels() const
{
- return mTextureSerial;
+ const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), 0);
+ if (mTarget == GL_TEXTURE_3D)
+ {
+ const int maxDim = std::max(std::max(baseImageDesc.size.width, baseImageDesc.size.height),
+ baseImageDesc.size.depth);
+ return log2(maxDim) + 1;
+ }
+ else
+ {
+ return log2(std::max(baseImageDesc.size.width, baseImageDesc.size.height)) + 1;
+ }
}
-unsigned int Texture::issueTextureSerial()
+egl::Surface *Texture::getBoundSurface() const
{
- return mCurrentTextureSerial++;
+ return mBoundSurface;
}
-bool Texture::isImmutable() const
+Error Texture::setImage(Context *context,
+ GLenum target,
+ size_t level,
+ GLenum internalFormat,
+ const Extents &size,
+ GLenum format,
+ GLenum type,
+ const uint8_t *pixels)
{
- return (mImmutableLevelCount > 0);
-}
+ ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
-int Texture::immutableLevelCount()
-{
- return mImmutableLevelCount;
-}
+ // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
+ releaseTexImageInternal();
+ orphanImages();
-Error Texture::setImage(GLenum target, size_t level, GLenum internalFormat, const Extents &size, GLenum format, GLenum type,
- const PixelUnpackState &unpack, const uint8_t *pixels)
-{
- ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
+ // Hack: allow nullptr for testing
+ if (context != nullptr)
+ {
+ // Sync the unpack state
+ context->syncRendererState(context->getState().unpackStateBitMask());
+ }
+ const PixelUnpackState defaultUnpack;
+ const PixelUnpackState &unpack = context ? context->getState().getUnpackState() : defaultUnpack;
Error error = mTexture->setImage(target, level, internalFormat, size, format, type, unpack, pixels);
if (error.isError())
{
return error;
}
- releaseTexImage();
-
setImageDesc(target, level, ImageDesc(size, GetSizedInternalFormat(internalFormat, type)));
return Error(GL_NO_ERROR);
}
-Error Texture::setSubImage(GLenum target, size_t level, const Box &area, GLenum format, GLenum type,
- const PixelUnpackState &unpack, const uint8_t *pixels)
+Error Texture::setSubImage(Context *context,
+ GLenum target,
+ size_t level,
+ const Box &area,
+ GLenum format,
+ GLenum type,
+ const uint8_t *pixels)
{
ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
+ // Sync the unpack state
+ context->syncRendererState(context->getState().unpackStateBitMask());
+
+ const PixelUnpackState &unpack = context->getState().getUnpackState();
return mTexture->setSubImage(target, level, area, format, type, unpack, pixels);
}
-Error Texture::setCompressedImage(GLenum target, size_t level, GLenum internalFormat, const Extents &size,
- const PixelUnpackState &unpack, const uint8_t *pixels)
+Error Texture::setCompressedImage(Context *context,
+ GLenum target,
+ size_t level,
+ GLenum internalFormat,
+ const Extents &size,
+ size_t imageSize,
+ const uint8_t *pixels)
{
ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
- Error error = mTexture->setCompressedImage(target, level, internalFormat, size, unpack, pixels);
+ // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
+ releaseTexImageInternal();
+ orphanImages();
+
+ // Sync the unpack state
+ context->syncRendererState(context->getState().unpackStateBitMask());
+
+ const PixelUnpackState &unpack = context->getState().getUnpackState();
+ Error error = mTexture->setCompressedImage(target, level, internalFormat, size, unpack, imageSize, pixels);
if (error.isError())
{
return error;
}
- releaseTexImage();
-
setImageDesc(target, level, ImageDesc(size, GetSizedInternalFormat(internalFormat, GL_UNSIGNED_BYTE)));
return Error(GL_NO_ERROR);
}
-Error Texture::setCompressedSubImage(GLenum target, size_t level, const Box &area, GLenum format,
- const PixelUnpackState &unpack, const uint8_t *pixels)
+Error Texture::setCompressedSubImage(Context *context,
+ GLenum target,
+ size_t level,
+ const Box &area,
+ GLenum format,
+ size_t imageSize,
+ const uint8_t *pixels)
{
ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
- return mTexture->setCompressedSubImage(target, level, area, format, unpack, pixels);
+ // Sync the unpack state
+ context->syncRendererState(context->getState().unpackStateBitMask());
+
+ const PixelUnpackState &unpack = context->getState().getUnpackState();
+ return mTexture->setCompressedSubImage(target, level, area, format, unpack, imageSize, pixels);
}
Error Texture::copyImage(GLenum target, size_t level, const Rectangle &sourceArea, GLenum internalFormat,
@@ -233,14 +472,16 @@ Error Texture::copyImage(GLenum target, size_t level, const Rectangle &sourceAre
{
ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
+ // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
+ releaseTexImageInternal();
+ orphanImages();
+
Error error = mTexture->copyImage(target, level, sourceArea, internalFormat, source);
if (error.isError())
{
return error;
}
- releaseTexImage();
-
setImageDesc(target, level, ImageDesc(Extents(sourceArea.width, sourceArea.height, 1),
GetSizedInternalFormat(internalFormat, GL_UNSIGNED_BYTE)));
@@ -259,32 +500,42 @@ Error Texture::setStorage(GLenum target, size_t levels, GLenum internalFormat, c
{
ASSERT(target == mTarget);
+ // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
+ releaseTexImageInternal();
+ orphanImages();
+
Error error = mTexture->setStorage(target, levels, internalFormat, size);
if (error.isError())
{
return error;
}
- releaseTexImage();
-
- mImmutableLevelCount = levels;
+ mTextureState.immutableFormat = true;
+ mTextureState.immutableLevels = static_cast<GLuint>(levels);
clearImageDescs();
setImageDescChain(levels, size, internalFormat);
return Error(GL_NO_ERROR);
}
-
Error Texture::generateMipmaps()
{
- Error error = mTexture->generateMipmaps();
+ // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
+ releaseTexImageInternal();
+
+ // EGL_KHR_gl_image states that images are only orphaned when generating mipmaps if the texture
+ // is not mip complete.
+ if (!isMipmapComplete())
+ {
+ orphanImages();
+ }
+
+ Error error = mTexture->generateMipmaps(mTextureState);
if (error.isError())
{
return error;
}
- releaseTexImage();
-
const ImageDesc &baseImageInfo = getImageDesc(getBaseImageTarget(), 0);
size_t mipLevels = log2(std::max(std::max(baseImageInfo.size.width, baseImageInfo.size.height), baseImageInfo.size.depth)) + 1;
setImageDescChain(mipLevels, baseImageInfo.size, baseImageInfo.internalFormat);
@@ -294,16 +545,17 @@ Error Texture::generateMipmaps()
void Texture::setImageDescChain(size_t levels, Extents baseSize, GLenum sizedInternalFormat)
{
- for (size_t level = 0; level < levels; level++)
+ for (int level = 0; level < static_cast<int>(levels); level++)
{
- Extents levelSize(std::max<size_t>(baseSize.width >> level, 1),
- std::max<size_t>(baseSize.height >> level, 1),
- (mTarget == GL_TEXTURE_2D_ARRAY) ? baseSize.depth : std::max<size_t>(baseSize.depth >> level, 1));
+ Extents levelSize(
+ std::max<int>(baseSize.width >> level, 1), std::max<int>(baseSize.height >> level, 1),
+ (mTarget == GL_TEXTURE_2D_ARRAY) ? baseSize.depth
+ : std::max<int>(baseSize.depth >> level, 1));
ImageDesc levelInfo(levelSize, sizedInternalFormat);
if (mTarget == GL_TEXTURE_CUBE_MAP)
{
- for (size_t face = FirstCubeMapTextureTarget; face <= LastCubeMapTextureTarget; face++)
+ for (GLenum face = FirstCubeMapTextureTarget; face <= LastCubeMapTextureTarget; face++)
{
setImageDesc(face, level, levelInfo);
}
@@ -316,7 +568,7 @@ void Texture::setImageDescChain(size_t levels, Extents baseSize, GLenum sizedInt
}
Texture::ImageDesc::ImageDesc()
- : size(0, 0, 0), internalFormat(GL_NONE)
+ : ImageDesc(Extents(0, 0, 0), GL_NONE)
{
}
@@ -355,11 +607,15 @@ void Texture::clearImageDescs()
mCompletenessCache.cacheValid = false;
}
-void Texture::bindTexImage(egl::Surface *surface)
+void Texture::bindTexImageFromSurface(egl::Surface *surface)
{
ASSERT(surface);
- releaseTexImage();
+ if (mBoundSurface)
+ {
+ releaseTexImageFromSurface();
+ }
+
mTexture->bindTexImage(surface);
mBoundSurface = surface;
@@ -370,40 +626,65 @@ void Texture::bindTexImage(egl::Surface *surface)
setImageDesc(mTarget, 0, desc);
}
-void Texture::releaseTexImage()
+void Texture::releaseTexImageFromSurface()
+{
+ ASSERT(mBoundSurface);
+ mBoundSurface = nullptr;
+ mTexture->releaseTexImage();
+
+ // Erase the image info for level 0
+ ASSERT(mTarget == GL_TEXTURE_2D);
+ clearImageDesc(mTarget, 0);
+}
+
+void Texture::releaseTexImageInternal()
{
if (mBoundSurface)
{
- mBoundSurface = NULL;
- mTexture->releaseTexImage();
+ // Notify the surface
+ mBoundSurface->releaseTexImageFromTexture();
- // Erase the image info for level 0
- ASSERT(mTarget == GL_TEXTURE_2D);
- clearImageDesc(mTarget, 0);
+ // Then, call the same method as from the surface
+ releaseTexImageFromSurface();
}
}
-GLenum Texture::getBaseImageTarget() const
+Error Texture::setEGLImageTarget(GLenum target, egl::Image *imageTarget)
{
- return mTarget == GL_TEXTURE_CUBE_MAP ? FirstCubeMapTextureTarget : mTarget;
-}
+ ASSERT(target == mTarget);
+ ASSERT(target == GL_TEXTURE_2D);
-size_t Texture::getExpectedMipLevels() const
-{
- const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), 0);
- if (mTarget == GL_TEXTURE_3D)
- {
- return log2(std::max(std::max(baseImageDesc.size.width, baseImageDesc.size.height), baseImageDesc.size.depth)) + 1;
- }
- else
+ // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
+ releaseTexImageInternal();
+ orphanImages();
+
+ Error error = mTexture->setEGLImageTarget(target, imageTarget);
+ if (error.isError())
{
- return log2(std::max(baseImageDesc.size.width, baseImageDesc.size.height)) + 1;
+ return error;
}
+
+ setTargetImage(imageTarget);
+
+ Extents size(static_cast<int>(imageTarget->getWidth()),
+ static_cast<int>(imageTarget->getHeight()), 1);
+ GLenum internalFormat = imageTarget->getInternalFormat();
+ GLenum type = GetInternalFormatInfo(internalFormat).type;
+
+ clearImageDescs();
+ setImageDesc(target, 0, ImageDesc(size, GetSizedInternalFormat(internalFormat, type)));
+
+ return Error(GL_NO_ERROR);
+}
+
+GLenum Texture::getBaseImageTarget() const
+{
+ return mTarget == GL_TEXTURE_CUBE_MAP ? FirstCubeMapTextureTarget : mTarget;
}
bool Texture::computeSamplerCompleteness(const SamplerState &samplerState, const Data &data) const
{
- const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), samplerState.baseLevel);
+ const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), mTextureState.baseLevel);
if (baseImageDesc.size.width == 0 || baseImageDesc.size.height == 0 || baseImageDesc.size.depth == 0)
{
return false;
@@ -440,7 +721,7 @@ bool Texture::computeSamplerCompleteness(const SamplerState &samplerState, const
}
}
- if (!computeMipmapCompleteness(samplerState))
+ if (!computeMipmapCompleteness())
{
return false;
}
@@ -474,19 +755,19 @@ bool Texture::computeSamplerCompleteness(const SamplerState &samplerState, const
return true;
}
-bool Texture::computeMipmapCompleteness(const gl::SamplerState &samplerState) const
+bool Texture::computeMipmapCompleteness() const
{
- size_t expectedMipLevels = getExpectedMipLevels();
+ size_t expectedMipLevels = getMipCompleteLevels();
- size_t maxLevel = std::min<size_t>(expectedMipLevels, samplerState.maxLevel + 1);
+ size_t maxLevel = std::min<size_t>(expectedMipLevels, mTextureState.maxLevel + 1);
- for (size_t level = samplerState.baseLevel; level < maxLevel; level++)
+ for (size_t level = mTextureState.baseLevel; level < maxLevel; level++)
{
if (mTarget == GL_TEXTURE_CUBE_MAP)
{
for (GLenum face = FirstCubeMapTextureTarget; face <= LastCubeMapTextureTarget; face++)
{
- if (!computeLevelCompleteness(face, level, samplerState))
+ if (!computeLevelCompleteness(face, level))
{
return false;
}
@@ -494,7 +775,7 @@ bool Texture::computeMipmapCompleteness(const gl::SamplerState &samplerState) co
}
else
{
- if (!computeLevelCompleteness(mTarget, level, samplerState))
+ if (!computeLevelCompleteness(mTarget, level))
{
return false;
}
@@ -504,47 +785,48 @@ bool Texture::computeMipmapCompleteness(const gl::SamplerState &samplerState) co
return true;
}
-
-bool Texture::computeLevelCompleteness(GLenum target, size_t level, const gl::SamplerState &samplerState) const
+bool Texture::computeLevelCompleteness(GLenum target, size_t level) const
{
ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
- if (isImmutable())
+ if (mTextureState.immutableFormat)
{
return true;
}
- const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), samplerState.baseLevel);
+ const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), mTextureState.baseLevel);
if (baseImageDesc.size.width == 0 || baseImageDesc.size.height == 0 || baseImageDesc.size.depth == 0)
{
return false;
}
- // The base image level is complete if the width and height are positive
- if (level == 0)
+ const ImageDesc &levelImageDesc = getImageDesc(target, level);
+ if (levelImageDesc.size.width == 0 || levelImageDesc.size.height == 0 ||
+ levelImageDesc.size.depth == 0)
{
- return true;
+ return false;
}
- const ImageDesc &levelImageDesc = getImageDesc(target, level);
if (levelImageDesc.internalFormat != baseImageDesc.internalFormat)
{
return false;
}
- if (levelImageDesc.size.width != std::max(1, baseImageDesc.size.width >> level))
+ ASSERT(level >= mTextureState.baseLevel);
+ const size_t relativeLevel = level - mTextureState.baseLevel;
+ if (levelImageDesc.size.width != std::max(1, baseImageDesc.size.width >> relativeLevel))
{
return false;
}
- if (levelImageDesc.size.height != std::max(1, baseImageDesc.size.height >> level))
+ if (levelImageDesc.size.height != std::max(1, baseImageDesc.size.height >> relativeLevel))
{
return false;
}
if (mTarget == GL_TEXTURE_3D)
{
- if (levelImageDesc.size.depth != std::max(1, baseImageDesc.size.depth >> level))
+ if (levelImageDesc.size.depth != std::max(1, baseImageDesc.size.depth >> relativeLevel))
{
return false;
}
@@ -570,4 +852,34 @@ Texture::SamplerCompletenessCache::SamplerCompletenessCache()
{
}
+Extents Texture::getAttachmentSize(const gl::FramebufferAttachment::Target &target) const
+{
+ return getImageDesc(target.textureIndex().type, target.textureIndex().mipIndex).size;
+}
+
+GLenum Texture::getAttachmentInternalFormat(const gl::FramebufferAttachment::Target &target) const
+{
+ return getInternalFormat(target.textureIndex().type, target.textureIndex().mipIndex);
+}
+
+GLsizei Texture::getAttachmentSamples(const gl::FramebufferAttachment::Target &/*target*/) const
+{
+ // Multisample textures not currently supported
+ return 0;
+}
+
+void Texture::onAttach()
+{
+ addRef();
+}
+
+void Texture::onDetach()
+{
+ release();
+}
+
+GLuint Texture::getId() const
+{
+ return id();
+}
}
diff --git a/src/3rdparty/angle/src/libANGLE/Texture.h b/src/3rdparty/angle/src/libANGLE/Texture.h
index b5a0717713..7ca8a456fc 100644
--- a/src/3rdparty/angle/src/libANGLE/Texture.h
+++ b/src/3rdparty/angle/src/libANGLE/Texture.h
@@ -9,17 +9,19 @@
#ifndef LIBANGLE_TEXTURE_H_
#define LIBANGLE_TEXTURE_H_
+#include <vector>
+#include <map>
+
+#include "angle_gl.h"
#include "common/debug.h"
-#include "libANGLE/RefCountObject.h"
-#include "libANGLE/angletypes.h"
+#include "libANGLE/Caps.h"
+#include "libANGLE/Debug.h"
#include "libANGLE/Constants.h"
+#include "libANGLE/Error.h"
+#include "libANGLE/FramebufferAttachment.h"
+#include "libANGLE/Image.h"
+#include "libANGLE/angletypes.h"
#include "libANGLE/renderer/TextureImpl.h"
-#include "libANGLE/Caps.h"
-
-#include "angle_gl.h"
-
-#include <vector>
-#include <map>
namespace egl
{
@@ -28,81 +30,172 @@ class Surface;
namespace gl
{
+class Context;
class Framebuffer;
struct Data;
-bool IsMipmapFiltered(const gl::SamplerState &samplerState);
+bool IsMipmapFiltered(const SamplerState &samplerState);
-class Texture final : public RefCountObject
+class Texture final : public egl::ImageSibling,
+ public FramebufferAttachmentObject,
+ public LabeledObject
{
public:
Texture(rx::TextureImpl *impl, GLuint id, GLenum target);
+ ~Texture() override;
- virtual ~Texture();
+ void setLabel(const std::string &label) override;
+ const std::string &getLabel() const override;
GLenum getTarget() const;
- const SamplerState &getSamplerState() const { return mSamplerState; }
- SamplerState &getSamplerState() { return mSamplerState; }
+ void setSwizzleRed(GLenum swizzleRed);
+ GLenum getSwizzleRed() const;
- void setUsage(GLenum usage);
- GLenum getUsage() const;
+ void setSwizzleGreen(GLenum swizzleGreen);
+ GLenum getSwizzleGreen() const;
- size_t getWidth(GLenum target, size_t level) const;
- size_t getHeight(GLenum target, size_t level) const;
- size_t getDepth(GLenum target, size_t level) const;
- GLenum getInternalFormat(GLenum target, size_t level) const;
+ void setSwizzleBlue(GLenum swizzleBlue);
+ GLenum getSwizzleBlue() const;
- bool isSamplerComplete(const SamplerState &samplerState, const Data &data) const;
- bool isCubeComplete() const;
+ void setSwizzleAlpha(GLenum swizzleAlpha);
+ GLenum getSwizzleAlpha() const;
+
+ void setMinFilter(GLenum minFilter);
+ GLenum getMinFilter() const;
- virtual Error setImage(GLenum target, size_t level, GLenum internalFormat, const Extents &size, GLenum format, GLenum type,
- const PixelUnpackState &unpack, const uint8_t *pixels);
- virtual Error setSubImage(GLenum target, size_t level, const Box &area, GLenum format, GLenum type,
- const PixelUnpackState &unpack, const uint8_t *pixels);
+ void setMagFilter(GLenum magFilter);
+ GLenum getMagFilter() const;
- virtual Error setCompressedImage(GLenum target, size_t level, GLenum internalFormat, const Extents &size,
- const PixelUnpackState &unpack, const uint8_t *pixels);
- virtual Error setCompressedSubImage(GLenum target, size_t level, const Box &area, GLenum format,
- const PixelUnpackState &unpack, const uint8_t *pixels);
+ void setWrapS(GLenum wrapS);
+ GLenum getWrapS() const;
- virtual Error copyImage(GLenum target, size_t level, const Rectangle &sourceArea, GLenum internalFormat,
- const Framebuffer *source);
- virtual Error copySubImage(GLenum target, size_t level, const Offset &destOffset, const Rectangle &sourceArea,
- const Framebuffer *source);
+ void setWrapT(GLenum wrapT);
+ GLenum getWrapT() const;
- virtual Error setStorage(GLenum target, size_t levels, GLenum internalFormat, const Extents &size);
+ void setWrapR(GLenum wrapR);
+ GLenum getWrapR() const;
- virtual Error generateMipmaps();
+ void setMaxAnisotropy(float maxAnisotropy);
+ float getMaxAnisotropy() const;
- // Texture serials provide a unique way of identifying a Texture that isn't a raw pointer.
- // "id" is not good enough, as Textures can be deleted, then re-allocated with the same id.
- unsigned int getTextureSerial() const;
+ void setMinLod(GLfloat minLod);
+ GLfloat getMinLod() const;
- bool isImmutable() const;
- GLsizei immutableLevelCount();
+ void setMaxLod(GLfloat maxLod);
+ GLfloat getMaxLod() const;
- void bindTexImage(egl::Surface *surface);
- void releaseTexImage();
+ void setCompareMode(GLenum compareMode);
+ GLenum getCompareMode() const;
+
+ void setCompareFunc(GLenum compareFunc);
+ GLenum getCompareFunc() const;
+
+ const SamplerState &getSamplerState() const;
+
+ void setBaseLevel(GLuint baseLevel);
+ GLuint getBaseLevel() const;
+
+ void setMaxLevel(GLuint maxLevel);
+ GLuint getMaxLevel() const;
+
+ bool getImmutableFormat() const;
+
+ GLuint getImmutableLevels() const;
+
+ void setUsage(GLenum usage);
+ GLenum getUsage() const;
+
+ const TextureState &getTextureState() const;
+
+ size_t getWidth(GLenum target, size_t level) const;
+ size_t getHeight(GLenum target, size_t level) const;
+ size_t getDepth(GLenum target, size_t level) const;
+ GLenum getInternalFormat(GLenum target, size_t level) const;
+
+ bool isSamplerComplete(const SamplerState &samplerState, const Data &data) const;
+ bool isMipmapComplete() const;
+ bool isCubeComplete() const;
+ size_t getMipCompleteLevels() const;
+
+ Error setImage(Context *context,
+ GLenum target,
+ size_t level,
+ GLenum internalFormat,
+ const Extents &size,
+ GLenum format,
+ GLenum type,
+ const uint8_t *pixels);
+ Error setSubImage(Context *context,
+ GLenum target,
+ size_t level,
+ const Box &area,
+ GLenum format,
+ GLenum type,
+ const uint8_t *pixels);
+
+ Error setCompressedImage(Context *context,
+ GLenum target,
+ size_t level,
+ GLenum internalFormat,
+ const Extents &size,
+ size_t imageSize,
+ const uint8_t *pixels);
+ Error setCompressedSubImage(Context *context,
+ GLenum target,
+ size_t level,
+ const Box &area,
+ GLenum format,
+ size_t imageSize,
+ const uint8_t *pixels);
+
+ Error copyImage(GLenum target,
+ size_t level,
+ const Rectangle &sourceArea,
+ GLenum internalFormat,
+ const Framebuffer *source);
+ Error copySubImage(GLenum target,
+ size_t level,
+ const Offset &destOffset,
+ const Rectangle &sourceArea,
+ const Framebuffer *source);
+
+ Error setStorage(GLenum target, size_t levels, GLenum internalFormat, const Extents &size);
+
+ Error setEGLImageTarget(GLenum target, egl::Image *imageTarget);
+
+ Error generateMipmaps();
+
+ egl::Surface *getBoundSurface() const;
rx::TextureImpl *getImplementation() { return mTexture; }
const rx::TextureImpl *getImplementation() const { return mTexture; }
- static const GLuint INCOMPLETE_TEXTURE_ID = static_cast<GLuint>(-1); // Every texture takes an id at creation time. The value is arbitrary because it is never registered with the resource manager.
+ // FramebufferAttachmentObject implementation
+ Extents getAttachmentSize(const FramebufferAttachment::Target &target) const override;
+ GLenum getAttachmentInternalFormat(const FramebufferAttachment::Target &target) const override;
+ GLsizei getAttachmentSamples(const FramebufferAttachment::Target &target) const override;
+
+ void onAttach() override;
+ void onDetach() override;
+ GLuint getId() const override;
private:
- static unsigned int issueTextureSerial();
+ rx::FramebufferAttachmentObjectImpl *getAttachmentImpl() const override { return mTexture; }
+
+ // ANGLE-only method, used internally
+ friend class egl::Surface;
+ void bindTexImageFromSurface(egl::Surface *surface);
+ void releaseTexImageFromSurface();
rx::TextureImpl *mTexture;
- SamplerState mSamplerState;
- GLenum mUsage;
+ std::string mLabel;
- GLsizei mImmutableLevelCount;
+ TextureState mTextureState;
GLenum mTarget;
-
struct ImageDesc
{
Extents size;
@@ -112,21 +205,18 @@ class Texture final : public RefCountObject
ImageDesc(const Extents &size, GLenum internalFormat);
};
- const unsigned int mTextureSerial;
- static unsigned int mCurrentTextureSerial;
-
GLenum getBaseImageTarget() const;
- size_t getExpectedMipLevels() const;
bool computeSamplerCompleteness(const SamplerState &samplerState, const Data &data) const;
- bool computeMipmapCompleteness(const gl::SamplerState &samplerState) const;
- bool computeLevelCompleteness(GLenum target, size_t level, const gl::SamplerState &samplerState) const;
+ bool computeMipmapCompleteness() const;
+ bool computeLevelCompleteness(GLenum target, size_t level) const;
const ImageDesc &getImageDesc(GLenum target, size_t level) const;
void setImageDesc(GLenum target, size_t level, const ImageDesc &desc);
void setImageDescChain(size_t levels, Extents baseSize, GLenum sizedInternalFormat);
void clearImageDesc(GLenum target, size_t level);
void clearImageDescs();
+ void releaseTexImageInternal();
std::vector<ImageDesc> mImageDescs;
diff --git a/src/3rdparty/angle/src/libANGLE/TransformFeedback.cpp b/src/3rdparty/angle/src/libANGLE/TransformFeedback.cpp
index 6effaca976..b7961971d0 100644
--- a/src/3rdparty/angle/src/libANGLE/TransformFeedback.cpp
+++ b/src/3rdparty/angle/src/libANGLE/TransformFeedback.cpp
@@ -5,67 +5,146 @@
//
#include "libANGLE/TransformFeedback.h"
+
+#include "libANGLE/Buffer.h"
+#include "libANGLE/Caps.h"
#include "libANGLE/renderer/TransformFeedbackImpl.h"
namespace gl
{
-TransformFeedback::TransformFeedback(rx::TransformFeedbackImpl* impl, GLuint id)
+TransformFeedback::TransformFeedback(rx::TransformFeedbackImpl *impl, GLuint id, const Caps &caps)
: RefCountObject(id),
- mTransformFeedback(impl),
- mStarted(GL_FALSE),
+ mImplementation(impl),
+ mLabel(),
+ mActive(false),
mPrimitiveMode(GL_NONE),
- mPaused(GL_FALSE)
+ mPaused(false),
+ mGenericBuffer(),
+ mIndexedBuffers(caps.maxTransformFeedbackSeparateAttributes)
{
ASSERT(impl != NULL);
}
TransformFeedback::~TransformFeedback()
{
- SafeDelete(mTransformFeedback);
+ mGenericBuffer.set(nullptr);
+ for (size_t i = 0; i < mIndexedBuffers.size(); i++)
+ {
+ mIndexedBuffers[i].set(nullptr);
+ }
+
+ SafeDelete(mImplementation);
}
-void TransformFeedback::start(GLenum primitiveMode)
+void TransformFeedback::setLabel(const std::string &label)
{
- mStarted = GL_TRUE;
- mPrimitiveMode = primitiveMode;
- mPaused = GL_FALSE;
- mTransformFeedback->begin(primitiveMode);
+ mLabel = label;
}
-void TransformFeedback::stop()
+const std::string &TransformFeedback::getLabel() const
{
- mStarted = GL_FALSE;
- mPrimitiveMode = GL_NONE;
- mPaused = GL_FALSE;
- mTransformFeedback->end();
+ return mLabel;
}
-GLboolean TransformFeedback::isStarted() const
+void TransformFeedback::begin(GLenum primitiveMode)
{
- return mStarted;
+ mActive = true;
+ mPrimitiveMode = primitiveMode;
+ mPaused = false;
+ mImplementation->begin(primitiveMode);
}
-GLenum TransformFeedback::getDrawMode() const
+void TransformFeedback::end()
{
- return mPrimitiveMode;
+ mActive = false;
+ mPrimitiveMode = GL_NONE;
+ mPaused = false;
+ mImplementation->end();
}
void TransformFeedback::pause()
{
- mPaused = GL_TRUE;
- mTransformFeedback->pause();
+ mPaused = true;
+ mImplementation->pause();
}
void TransformFeedback::resume()
{
- mPaused = GL_FALSE;
- mTransformFeedback->resume();
+ mPaused = false;
+ mImplementation->resume();
+}
+
+bool TransformFeedback::isActive() const
+{
+ return mActive;
}
-GLboolean TransformFeedback::isPaused() const
+bool TransformFeedback::isPaused() const
{
return mPaused;
}
+GLenum TransformFeedback::getPrimitiveMode() const
+{
+ return mPrimitiveMode;
+}
+
+void TransformFeedback::bindGenericBuffer(Buffer *buffer)
+{
+ mGenericBuffer.set(buffer);
+ mImplementation->bindGenericBuffer(mGenericBuffer);
+}
+
+void TransformFeedback::detachBuffer(GLuint bufferName)
+{
+ for (size_t index = 0; index < mIndexedBuffers.size(); index++)
+ {
+ if (mIndexedBuffers[index].id() == bufferName)
+ {
+ mIndexedBuffers[index].set(nullptr);
+ mImplementation->bindIndexedBuffer(index, mIndexedBuffers[index]);
+ }
+ }
+
+ if (mGenericBuffer.id() == bufferName)
+ {
+ mGenericBuffer.set(nullptr);
+ mImplementation->bindGenericBuffer(mGenericBuffer);
+ }
+}
+
+const BindingPointer<Buffer> &TransformFeedback::getGenericBuffer() const
+{
+ return mGenericBuffer;
+}
+
+void TransformFeedback::bindIndexedBuffer(size_t index, Buffer *buffer, size_t offset, size_t size)
+{
+ ASSERT(index < mIndexedBuffers.size());
+ mIndexedBuffers[index].set(buffer, offset, size);
+ mImplementation->bindIndexedBuffer(index, mIndexedBuffers[index]);
+}
+
+const OffsetBindingPointer<Buffer> &TransformFeedback::getIndexedBuffer(size_t index) const
+{
+ ASSERT(index < mIndexedBuffers.size());
+ return mIndexedBuffers[index];
+}
+
+size_t TransformFeedback::getIndexedBufferCount() const
+{
+ return mIndexedBuffers.size();
+}
+
+rx::TransformFeedbackImpl *TransformFeedback::getImplementation()
+{
+ return mImplementation;
+}
+
+const rx::TransformFeedbackImpl *TransformFeedback::getImplementation() const
+{
+ return mImplementation;
+}
+
}
diff --git a/src/3rdparty/angle/src/libANGLE/TransformFeedback.h b/src/3rdparty/angle/src/libANGLE/TransformFeedback.h
index 7673db93ff..098e4ea4d6 100644
--- a/src/3rdparty/angle/src/libANGLE/TransformFeedback.h
+++ b/src/3rdparty/angle/src/libANGLE/TransformFeedback.h
@@ -10,6 +10,7 @@
#include "libANGLE/RefCountObject.h"
#include "common/angleutils.h"
+#include "libANGLE/Debug.h"
#include "angle_gl.h"
@@ -20,29 +21,50 @@ class TransformFeedbackImpl;
namespace gl
{
+class Buffer;
+struct Caps;
-class TransformFeedback : public RefCountObject
+class TransformFeedback final : public RefCountObject, public LabeledObject
{
public:
- TransformFeedback(rx::TransformFeedbackImpl* impl, GLuint id);
+ TransformFeedback(rx::TransformFeedbackImpl* impl, GLuint id, const Caps &caps);
virtual ~TransformFeedback();
- void start(GLenum primitiveMode);
- void stop();
- GLboolean isStarted() const;
-
- GLenum getDrawMode() const;
+ void setLabel(const std::string &label) override;
+ const std::string &getLabel() const override;
+ void begin(GLenum primitiveMode);
+ void end();
void pause();
void resume();
- GLboolean isPaused() const;
+
+ bool isActive() const;
+ bool isPaused() const;
+ GLenum getPrimitiveMode() const;
+
+ void bindGenericBuffer(Buffer *buffer);
+ const BindingPointer<Buffer> &getGenericBuffer() const;
+
+ void bindIndexedBuffer(size_t index, Buffer *buffer, size_t offset, size_t size);
+ const OffsetBindingPointer<Buffer> &getIndexedBuffer(size_t index) const;
+ size_t getIndexedBufferCount() const;
+
+ void detachBuffer(GLuint bufferName);
+
+ rx::TransformFeedbackImpl *getImplementation();
+ const rx::TransformFeedbackImpl *getImplementation() const;
private:
- rx::TransformFeedbackImpl* mTransformFeedback;
+ rx::TransformFeedbackImpl* mImplementation;
- GLboolean mStarted;
+ std::string mLabel;
+
+ bool mActive;
GLenum mPrimitiveMode;
- GLboolean mPaused;
+ bool mPaused;
+
+ BindingPointer<Buffer> mGenericBuffer;
+ std::vector<OffsetBindingPointer<Buffer>> mIndexedBuffers;
};
}
diff --git a/src/3rdparty/angle/src/libANGLE/Uniform.cpp b/src/3rdparty/angle/src/libANGLE/Uniform.cpp
index f161b9d6bd..bfae3c014f 100644
--- a/src/3rdparty/angle/src/libANGLE/Uniform.cpp
+++ b/src/3rdparty/angle/src/libANGLE/Uniform.cpp
@@ -13,55 +13,51 @@
namespace gl
{
-LinkedUniform::LinkedUniform(GLenum type, GLenum precision, const std::string &name, unsigned int arraySize,
- const int blockIndex, const sh::BlockMemberInfo &blockInfo)
- : type(type),
- precision(precision),
- name(name),
- arraySize(arraySize),
- blockIndex(blockIndex),
- blockInfo(blockInfo),
- data(NULL),
- dirty(true),
- psRegisterIndex(GL_INVALID_INDEX),
- vsRegisterIndex(GL_INVALID_INDEX),
- registerCount(0),
- registerElement(0)
-{
- // We use data storage for default block uniforms to cache values that are sent to D3D during rendering
- // Uniform blocks/buffers are treated separately by the Renderer (ES3 path only)
- if (isInDefaultBlock())
- {
- size_t bytes = dataSize();
- data = new unsigned char[bytes];
- memset(data, 0, bytes);
- registerCount = VariableRowCount(type) * elementCount();
- }
+LinkedUniform::LinkedUniform()
+ : blockIndex(-1), blockInfo(sh::BlockMemberInfo::getDefaultBlockInfo())
+{
}
-LinkedUniform::~LinkedUniform()
+LinkedUniform::LinkedUniform(GLenum typeIn,
+ GLenum precisionIn,
+ const std::string &nameIn,
+ unsigned int arraySizeIn,
+ const int blockIndexIn,
+ const sh::BlockMemberInfo &blockInfoIn)
+ : blockIndex(blockIndexIn), blockInfo(blockInfoIn)
{
- delete[] data;
+ type = typeIn;
+ precision = precisionIn;
+ name = nameIn;
+ arraySize = arraySizeIn;
}
-bool LinkedUniform::isArray() const
+LinkedUniform::LinkedUniform(const sh::Uniform &uniform)
+ : sh::Uniform(uniform), blockIndex(-1), blockInfo(sh::BlockMemberInfo::getDefaultBlockInfo())
{
- return arraySize > 0;
}
-unsigned int LinkedUniform::elementCount() const
+LinkedUniform::LinkedUniform(const LinkedUniform &uniform)
+ : sh::Uniform(uniform), blockIndex(uniform.blockIndex), blockInfo(uniform.blockInfo)
{
- return arraySize > 0 ? arraySize : 1;
+ // This function is not intended to be called during runtime.
+ ASSERT(uniform.mLazyData.empty());
}
-bool LinkedUniform::isReferencedByVertexShader() const
+LinkedUniform &LinkedUniform::operator=(const LinkedUniform &uniform)
{
- return vsRegisterIndex != GL_INVALID_INDEX;
+ // This function is not intended to be called during runtime.
+ ASSERT(uniform.mLazyData.empty());
+
+ sh::Uniform::operator=(uniform);
+ blockIndex = uniform.blockIndex;
+ blockInfo = uniform.blockInfo;
+
+ return *this;
}
-bool LinkedUniform::isReferencedByFragmentShader() const
+LinkedUniform::~LinkedUniform()
{
- return psRegisterIndex != GL_INVALID_INDEX;
}
bool LinkedUniform::isInDefaultBlock() const
@@ -72,7 +68,30 @@ bool LinkedUniform::isInDefaultBlock() const
size_t LinkedUniform::dataSize() const
{
ASSERT(type != GL_STRUCT_ANGLEX);
- return VariableInternalSize(type) * elementCount();
+ if (mLazyData.empty())
+ {
+ mLazyData.resize(VariableExternalSize(type) * elementCount());
+ ASSERT(!mLazyData.empty());
+ }
+
+ return mLazyData.size();
+}
+
+uint8_t *LinkedUniform::data()
+{
+ if (mLazyData.empty())
+ {
+ // dataSize() will init the data store.
+ size_t size = dataSize();
+ memset(mLazyData.data(), 0, size);
+ }
+
+ return mLazyData.data();
+}
+
+const uint8_t *LinkedUniform::data() const
+{
+ return const_cast<LinkedUniform *>(this)->data();
}
bool LinkedUniform::isSampler() const
@@ -80,28 +99,51 @@ bool LinkedUniform::isSampler() const
return IsSamplerType(type);
}
-UniformBlock::UniformBlock(const std::string &name, unsigned int elementIndex, unsigned int dataSize)
- : name(name),
- elementIndex(elementIndex),
- dataSize(dataSize),
- psRegisterIndex(GL_INVALID_INDEX),
- vsRegisterIndex(GL_INVALID_INDEX)
+bool LinkedUniform::isField() const
{
+ return name.find('.') != std::string::npos;
}
-bool UniformBlock::isArrayElement() const
+size_t LinkedUniform::getElementSize() const
{
- return elementIndex != GL_INVALID_INDEX;
+ return VariableExternalSize(type);
}
-bool UniformBlock::isReferencedByVertexShader() const
+uint8_t *LinkedUniform::getDataPtrToElement(size_t elementIndex)
{
- return vsRegisterIndex != GL_INVALID_INDEX;
+ ASSERT((!isArray() && elementIndex == 0) || (isArray() && elementIndex < arraySize));
+ return data() + getElementSize() * elementIndex;
}
-bool UniformBlock::isReferencedByFragmentShader() const
+const uint8_t *LinkedUniform::getDataPtrToElement(size_t elementIndex) const
{
- return psRegisterIndex != GL_INVALID_INDEX;
+ return const_cast<LinkedUniform *>(this)->getDataPtrToElement(elementIndex);
}
+UniformBlock::UniformBlock()
+ : isArray(false), arrayElement(0), dataSize(0), vertexStaticUse(false), fragmentStaticUse(false)
+{
+}
+
+UniformBlock::UniformBlock(const std::string &nameIn, bool isArrayIn, unsigned int arrayElementIn)
+ : name(nameIn),
+ isArray(isArrayIn),
+ arrayElement(arrayElementIn),
+ dataSize(0),
+ vertexStaticUse(false),
+ fragmentStaticUse(false)
+{
+}
+
+std::string UniformBlock::nameWithArrayIndex() const
+{
+ std::stringstream fullNameStr;
+ fullNameStr << name;
+ if (isArray)
+ {
+ fullNameStr << "[" << arrayElement << "]";
+ }
+
+ return fullNameStr.str();
+}
}
diff --git a/src/3rdparty/angle/src/libANGLE/Uniform.h b/src/3rdparty/angle/src/libANGLE/Uniform.h
index dcf30f23cc..e62a583f3d 100644
--- a/src/3rdparty/angle/src/libANGLE/Uniform.h
+++ b/src/3rdparty/angle/src/libANGLE/Uniform.h
@@ -12,6 +12,7 @@
#include "angle_gl.h"
#include "common/debug.h"
+#include "common/MemoryBuffer.h"
#include "compiler/translator/blocklayout.h"
#include "libANGLE/angletypes.h"
@@ -19,57 +20,51 @@ namespace gl
{
// Helper struct representing a single shader uniform
-struct LinkedUniform : angle::NonCopyable
+struct LinkedUniform : public sh::Uniform
{
+ LinkedUniform();
LinkedUniform(GLenum type, GLenum precision, const std::string &name, unsigned int arraySize, const int blockIndex, const sh::BlockMemberInfo &blockInfo);
-
+ LinkedUniform(const sh::Uniform &uniform);
+ LinkedUniform(const LinkedUniform &uniform);
+ LinkedUniform &operator=(const LinkedUniform &uniform);
~LinkedUniform();
- bool isArray() const;
- unsigned int elementCount() const;
- bool isReferencedByVertexShader() const;
- bool isReferencedByFragmentShader() const;
- bool isInDefaultBlock() const;
size_t dataSize() const;
+ uint8_t *data();
+ const uint8_t *data() const;
bool isSampler() const;
+ bool isInDefaultBlock() const;
+ bool isField() const;
+ size_t getElementSize() const;
+ uint8_t *getDataPtrToElement(size_t elementIndex);
+ const uint8_t *getDataPtrToElement(size_t elementIndex) const;
- const GLenum type;
- const GLenum precision;
- const std::string name;
- const unsigned int arraySize;
- const int blockIndex;
- const sh::BlockMemberInfo blockInfo;
-
- unsigned char *data;
- bool dirty;
-
- unsigned int psRegisterIndex;
- unsigned int vsRegisterIndex;
- unsigned int registerCount;
+ int blockIndex;
+ sh::BlockMemberInfo blockInfo;
- // Register "elements" are used for uniform structs in ES3, to appropriately identify single uniforms
- // inside aggregate types, which are packed according C-like structure rules.
- unsigned int registerElement;
+ private:
+ mutable rx::MemoryBuffer mLazyData;
};
// Helper struct representing a single shader uniform block
-struct UniformBlock : angle::NonCopyable
+struct UniformBlock
{
- // use GL_INVALID_INDEX for non-array elements
- UniformBlock(const std::string &name, unsigned int elementIndex, unsigned int dataSize);
+ UniformBlock();
+ UniformBlock(const std::string &nameIn, bool isArrayIn, unsigned int arrayElementIn);
+ UniformBlock(const UniformBlock &other) = default;
+ UniformBlock &operator=(const UniformBlock &other) = default;
- bool isArrayElement() const;
- bool isReferencedByVertexShader() const;
- bool isReferencedByFragmentShader() const;
+ std::string nameWithArrayIndex() const;
- const std::string name;
- const unsigned int elementIndex;
- const unsigned int dataSize;
+ std::string name;
+ bool isArray;
+ unsigned int arrayElement;
+ unsigned int dataSize;
- std::vector<unsigned int> memberUniformIndexes;
+ bool vertexStaticUse;
+ bool fragmentStaticUse;
- unsigned int psRegisterIndex;
- unsigned int vsRegisterIndex;
+ std::vector<unsigned int> memberUniformIndexes;
};
}
diff --git a/src/3rdparty/angle/src/libANGLE/Version.h b/src/3rdparty/angle/src/libANGLE/Version.h
new file mode 100644
index 0000000000..72dfbb6b8d
--- /dev/null
+++ b/src/3rdparty/angle/src/libANGLE/Version.h
@@ -0,0 +1,33 @@
+//
+// 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.
+//
+
+// Version.h: Encapsulation of a GL version.
+
+#ifndef LIBANGLE_VERSION_H_
+#define LIBANGLE_VERSION_H_
+
+#include <angle_gl.h>
+
+namespace gl
+{
+
+struct Version
+{
+ Version();
+ Version(GLuint major, GLuint minor);
+
+ GLuint major;
+ GLuint minor;
+};
+
+bool operator>=(const Version &a, const Version &b);
+bool operator<(const Version &a, const Version &b);
+
+}
+
+#include "Version.inl"
+
+#endif // LIBANGLE_VERSION_H_
diff --git a/src/3rdparty/angle/src/libANGLE/Version.inl b/src/3rdparty/angle/src/libANGLE/Version.inl
new file mode 100644
index 0000000000..f64f7cae77
--- /dev/null
+++ b/src/3rdparty/angle/src/libANGLE/Version.inl
@@ -0,0 +1,33 @@
+//
+// 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.
+//
+
+// Version.inl: Encapsulation of a GL version.
+
+namespace gl
+{
+
+inline Version::Version()
+ : Version(0, 0)
+{
+}
+
+inline Version::Version(GLuint major_, GLuint minor_)
+{
+ major = major_;
+ minor = minor_;
+}
+
+inline bool operator>=(const Version &a, const Version &b)
+{
+ return a.major > b.major || (a.major == b.major && a.minor >= b.minor);
+}
+
+inline bool operator<(const Version &a, const Version &b)
+{
+ return !(a >= b);
+}
+
+}
diff --git a/src/3rdparty/angle/src/libANGLE/VertexArray.cpp b/src/3rdparty/angle/src/libANGLE/VertexArray.cpp
index f0aded905d..8d51e9b469 100644
--- a/src/3rdparty/angle/src/libANGLE/VertexArray.cpp
+++ b/src/3rdparty/angle/src/libANGLE/VertexArray.cpp
@@ -8,28 +8,36 @@
#include "libANGLE/VertexArray.h"
#include "libANGLE/Buffer.h"
+#include "libANGLE/renderer/ImplFactory.h"
#include "libANGLE/renderer/VertexArrayImpl.h"
namespace gl
{
-VertexArray::VertexArray(rx::VertexArrayImpl *impl, GLuint id, size_t maxAttribs)
- : mId(id),
- mVertexArray(impl),
- mVertexAttributes(maxAttribs)
+VertexArray::Data::Data(size_t maxAttribs)
+ : mLabel(), mVertexAttributes(maxAttribs), mMaxEnabledAttribute(0)
{
- ASSERT(impl != NULL);
}
-VertexArray::~VertexArray()
+VertexArray::Data::~Data()
{
- SafeDelete(mVertexArray);
-
for (size_t i = 0; i < getMaxAttribs(); i++)
{
- mVertexAttributes[i].buffer.set(NULL);
+ mVertexAttributes[i].buffer.set(nullptr);
}
- mElementArrayBuffer.set(NULL);
+ mElementArrayBuffer.set(nullptr);
+}
+
+VertexArray::VertexArray(rx::ImplFactory *factory, GLuint id, size_t maxAttribs)
+ : mId(id),
+ mVertexArray(factory->createVertexArray(mData)),
+ mData(maxAttribs)
+{
+}
+
+VertexArray::~VertexArray()
+{
+ SafeDelete(mVertexArray);
}
GLuint VertexArray::id() const
@@ -37,65 +45,96 @@ GLuint VertexArray::id() const
return mId;
}
+void VertexArray::setLabel(const std::string &label)
+{
+ mData.mLabel = label;
+}
+
+const std::string &VertexArray::getLabel() const
+{
+ return mData.mLabel;
+}
+
void VertexArray::detachBuffer(GLuint bufferName)
{
for (size_t attribute = 0; attribute < getMaxAttribs(); attribute++)
{
- if (mVertexAttributes[attribute].buffer.id() == bufferName)
+ if (mData.mVertexAttributes[attribute].buffer.id() == bufferName)
{
- mVertexAttributes[attribute].buffer.set(NULL);
+ mData.mVertexAttributes[attribute].buffer.set(nullptr);
}
}
- if (mElementArrayBuffer.id() == bufferName)
+ if (mData.mElementArrayBuffer.id() == bufferName)
{
- mElementArrayBuffer.set(NULL);
+ mData.mElementArrayBuffer.set(nullptr);
}
}
-const VertexAttribute& VertexArray::getVertexAttribute(size_t attributeIndex) const
+const VertexAttribute &VertexArray::getVertexAttribute(size_t attributeIndex) const
{
ASSERT(attributeIndex < getMaxAttribs());
- return mVertexAttributes[attributeIndex];
+ return mData.mVertexAttributes[attributeIndex];
}
-const std::vector<VertexAttribute> &VertexArray::getVertexAttributes() const
-{
- return mVertexAttributes;
-}
-
-void VertexArray::setVertexAttribDivisor(GLuint index, GLuint divisor)
+void VertexArray::setVertexAttribDivisor(size_t index, GLuint divisor)
{
ASSERT(index < getMaxAttribs());
- mVertexAttributes[index].divisor = divisor;
- mVertexArray->setAttributeDivisor(index, divisor);
+ mData.mVertexAttributes[index].divisor = divisor;
+ mDirtyBits.set(DIRTY_BIT_ATTRIB_0_DIVISOR + index);
}
-void VertexArray::enableAttribute(unsigned int attributeIndex, bool enabledState)
+void VertexArray::enableAttribute(size_t attributeIndex, bool enabledState)
{
ASSERT(attributeIndex < getMaxAttribs());
- mVertexAttributes[attributeIndex].enabled = enabledState;
- mVertexArray->enableAttribute(attributeIndex, enabledState);
+ mData.mVertexAttributes[attributeIndex].enabled = enabledState;
+ mDirtyBits.set(DIRTY_BIT_ATTRIB_0_ENABLED + attributeIndex);
+
+ // Update state cache
+ if (enabledState)
+ {
+ mData.mMaxEnabledAttribute = std::max(attributeIndex + 1, mData.mMaxEnabledAttribute);
+ }
+ else if (mData.mMaxEnabledAttribute == attributeIndex + 1)
+ {
+ while (mData.mMaxEnabledAttribute > 0 &&
+ !mData.mVertexAttributes[mData.mMaxEnabledAttribute - 1].enabled)
+ {
+ --mData.mMaxEnabledAttribute;
+ }
+ }
}
-void VertexArray::setAttributeState(unsigned int attributeIndex, gl::Buffer *boundBuffer, GLint size, GLenum type,
+void VertexArray::setAttributeState(size_t attributeIndex, gl::Buffer *boundBuffer, GLint size, GLenum type,
bool normalized, bool pureInteger, GLsizei stride, const void *pointer)
{
ASSERT(attributeIndex < getMaxAttribs());
- mVertexAttributes[attributeIndex].buffer.set(boundBuffer);
- mVertexAttributes[attributeIndex].size = size;
- mVertexAttributes[attributeIndex].type = type;
- mVertexAttributes[attributeIndex].normalized = normalized;
- mVertexAttributes[attributeIndex].pureInteger = pureInteger;
- mVertexAttributes[attributeIndex].stride = stride;
- mVertexAttributes[attributeIndex].pointer = pointer;
- mVertexArray->setAttribute(attributeIndex, mVertexAttributes[attributeIndex]);
+
+ VertexAttribute *attrib = &mData.mVertexAttributes[attributeIndex];
+
+ attrib->buffer.set(boundBuffer);
+ attrib->size = size;
+ attrib->type = type;
+ attrib->normalized = normalized;
+ attrib->pureInteger = pureInteger;
+ attrib->stride = stride;
+ attrib->pointer = pointer;
+ mDirtyBits.set(DIRTY_BIT_ATTRIB_0_POINTER + attributeIndex);
}
void VertexArray::setElementArrayBuffer(Buffer *buffer)
{
- mElementArrayBuffer.set(buffer);
- mVertexArray->setElementArrayBuffer(buffer);
+ mData.mElementArrayBuffer.set(buffer);
+ mDirtyBits.set(DIRTY_BIT_ELEMENT_ARRAY_BUFFER);
+}
+
+void VertexArray::syncImplState()
+{
+ if (mDirtyBits.any())
+ {
+ mVertexArray->syncState(mDirtyBits);
+ mDirtyBits.reset();
+ }
}
}
diff --git a/src/3rdparty/angle/src/libANGLE/VertexArray.h b/src/3rdparty/angle/src/libANGLE/VertexArray.h
index 5c79b9953d..6bc267d399 100644
--- a/src/3rdparty/angle/src/libANGLE/VertexArray.h
+++ b/src/3rdparty/angle/src/libANGLE/VertexArray.h
@@ -15,12 +15,15 @@
#include "libANGLE/RefCountObject.h"
#include "libANGLE/Constants.h"
+#include "libANGLE/Debug.h"
+#include "libANGLE/State.h"
#include "libANGLE/VertexAttribute.h"
#include <vector>
namespace rx
{
+class ImplFactory;
class VertexArrayImpl;
}
@@ -28,37 +31,93 @@ namespace gl
{
class Buffer;
-class VertexArray
+class VertexArray final : public LabeledObject
{
public:
- VertexArray(rx::VertexArrayImpl *impl, GLuint id, size_t maxAttribs);
+ VertexArray(rx::ImplFactory *factory, GLuint id, size_t maxAttribs);
~VertexArray();
GLuint id() const;
- const VertexAttribute& getVertexAttribute(size_t attributeIndex) const;
- const std::vector<VertexAttribute> &getVertexAttributes() const;
+ void setLabel(const std::string &label) override;
+ const std::string &getLabel() const override;
+
+ const VertexAttribute &getVertexAttribute(size_t attributeIndex) const;
void detachBuffer(GLuint bufferName);
- void setVertexAttribDivisor(GLuint index, GLuint divisor);
- void enableAttribute(unsigned int attributeIndex, bool enabledState);
- void setAttributeState(unsigned int attributeIndex, gl::Buffer *boundBuffer, GLint size, GLenum type,
+ void setVertexAttribDivisor(size_t index, GLuint divisor);
+ void enableAttribute(size_t attributeIndex, bool enabledState);
+ void setAttributeState(size_t attributeIndex, gl::Buffer *boundBuffer, GLint size, GLenum type,
bool normalized, bool pureInteger, GLsizei stride, const void *pointer);
- Buffer *getElementArrayBuffer() const { return mElementArrayBuffer.get(); }
void setElementArrayBuffer(Buffer *buffer);
- GLuint getElementArrayBufferId() const { return mElementArrayBuffer.id(); }
- size_t getMaxAttribs() const { return mVertexAttributes.size(); }
+
+ const BindingPointer<Buffer> &getElementArrayBuffer() const { return mData.getElementArrayBuffer(); }
+ size_t getMaxAttribs() const { return mData.getVertexAttributes().size(); }
+ const std::vector<VertexAttribute> &getVertexAttributes() const { return mData.getVertexAttributes(); }
rx::VertexArrayImpl *getImplementation() { return mVertexArray; }
const rx::VertexArrayImpl *getImplementation() const { return mVertexArray; }
+ size_t getMaxEnabledAttribute() const { return mData.getMaxEnabledAttribute(); }
+
+ class Data final : public angle::NonCopyable
+ {
+ public:
+ explicit Data(size_t maxAttribs);
+ ~Data();
+
+ const std::string &getLabel() const { return mLabel; }
+
+ const BindingPointer<Buffer> &getElementArrayBuffer() const { return mElementArrayBuffer; }
+ size_t getMaxAttribs() const { return mVertexAttributes.size(); }
+ size_t getMaxEnabledAttribute() const { return mMaxEnabledAttribute; }
+ const std::vector<VertexAttribute> &getVertexAttributes() const { return mVertexAttributes; }
+ const VertexAttribute &getVertexAttribute(size_t index) const
+ {
+ return mVertexAttributes[index];
+ }
+
+ private:
+ friend class VertexArray;
+ std::string mLabel;
+ std::vector<VertexAttribute> mVertexAttributes;
+ BindingPointer<Buffer> mElementArrayBuffer;
+ size_t mMaxEnabledAttribute;
+ };
+
+ enum DirtyBitType
+ {
+ DIRTY_BIT_ELEMENT_ARRAY_BUFFER,
+
+ // Reserve bits for enabled flags
+ DIRTY_BIT_ATTRIB_0_ENABLED,
+ DIRTY_BIT_ATTRIB_MAX_ENABLED = DIRTY_BIT_ATTRIB_0_ENABLED + gl::MAX_VERTEX_ATTRIBS,
+
+ // Reserve bits for attrib pointers
+ DIRTY_BIT_ATTRIB_0_POINTER = DIRTY_BIT_ATTRIB_MAX_ENABLED,
+ DIRTY_BIT_ATTRIB_MAX_POINTER = DIRTY_BIT_ATTRIB_0_POINTER + gl::MAX_VERTEX_ATTRIBS,
+
+ // Reserve bits for divisors
+ DIRTY_BIT_ATTRIB_0_DIVISOR = DIRTY_BIT_ATTRIB_MAX_POINTER,
+ DIRTY_BIT_ATTRIB_MAX_DIVISOR = DIRTY_BIT_ATTRIB_0_DIVISOR + gl::MAX_VERTEX_ATTRIBS,
+
+ DIRTY_BIT_UNKNOWN = DIRTY_BIT_ATTRIB_MAX_DIVISOR,
+ DIRTY_BIT_MAX = DIRTY_BIT_UNKNOWN,
+ };
+
+ typedef std::bitset<DIRTY_BIT_MAX> DirtyBits;
+
+ void syncImplState();
+ bool hasAnyDirtyBit() const { return mDirtyBits.any(); }
+
private:
GLuint mId;
rx::VertexArrayImpl *mVertexArray;
- std::vector<VertexAttribute> mVertexAttributes;
- BindingPointer<Buffer> mElementArrayBuffer;
+
+ Data mData;
+ DirtyBits mDirtyBits;
};
}
diff --git a/src/3rdparty/angle/src/libANGLE/VertexAttribute.cpp b/src/3rdparty/angle/src/libANGLE/VertexAttribute.cpp
index 19934e7fac..13d78fd13c 100644
--- a/src/3rdparty/angle/src/libANGLE/VertexAttribute.cpp
+++ b/src/3rdparty/angle/src/libANGLE/VertexAttribute.cpp
@@ -23,24 +23,6 @@ VertexAttribute::VertexAttribute()
{
}
-bool operator==(const VertexAttribute &a, const VertexAttribute &b)
-{
- return a.enabled == b.enabled &&
- a.type == b.type &&
- a.size == b.size &&
- a.normalized == b.normalized &&
- a.pureInteger == b.pureInteger &&
- a.stride == b.stride &&
- a.pointer == b.pointer &&
- a.buffer.get() == b.buffer.get() &&
- a.divisor == b.divisor;
-}
-
-bool operator!=(const VertexAttribute &a, const VertexAttribute &b)
-{
- return !(a == b);
-}
-
size_t ComputeVertexAttributeTypeSize(const VertexAttribute& attrib)
{
GLuint size = attrib.size;
@@ -70,4 +52,23 @@ size_t ComputeVertexAttributeStride(const VertexAttribute& attrib)
return attrib.stride ? attrib.stride : ComputeVertexAttributeTypeSize(attrib);
}
+size_t ComputeVertexAttributeElementCount(const VertexAttribute &attrib,
+ size_t drawCount,
+ size_t instanceCount)
+{
+ // For instanced rendering, we draw "instanceDrawCount" sets of "vertexDrawCount" vertices.
+ //
+ // A vertex attribute with a positive divisor loads one instanced vertex for every set of
+ // non-instanced vertices, and the instanced vertex index advances once every "mDivisor"
+ // instances.
+ if (instanceCount > 0 && attrib.divisor > 0)
+ {
+ // When instanceDrawCount is not a multiple attrib.divisor, the division must round up.
+ // For instance, with 5 non-instanced vertices and a divisor equal to 3, we need 2 instanced
+ // vertices.
+ return (instanceCount + attrib.divisor - 1u) / attrib.divisor;
+ }
+
+ return drawCount;
+}
}
diff --git a/src/3rdparty/angle/src/libANGLE/VertexAttribute.h b/src/3rdparty/angle/src/libANGLE/VertexAttribute.h
index bdffe97466..d1ee1b47a2 100644
--- a/src/3rdparty/angle/src/libANGLE/VertexAttribute.h
+++ b/src/3rdparty/angle/src/libANGLE/VertexAttribute.h
@@ -40,34 +40,13 @@ bool operator==(const VertexAttribute &a, const VertexAttribute &b);
bool operator!=(const VertexAttribute &a, const VertexAttribute &b);
template <typename T>
-T QuerySingleVertexAttributeParameter(const VertexAttribute& attrib, GLenum pname)
-{
- switch (pname)
- {
- case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
- return static_cast<T>(attrib.enabled ? GL_TRUE : GL_FALSE);
- case GL_VERTEX_ATTRIB_ARRAY_SIZE:
- return static_cast<T>(attrib.size);
- case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
- return static_cast<T>(attrib.stride);
- case GL_VERTEX_ATTRIB_ARRAY_TYPE:
- return static_cast<T>(attrib.type);
- case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
- return static_cast<T>(attrib.normalized ? GL_TRUE : GL_FALSE);
- case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
- return static_cast<T>(attrib.buffer.id());
- case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
- return static_cast<T>(attrib.divisor);
- case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
- return static_cast<T>(attrib.pureInteger ? GL_TRUE : GL_FALSE);
- default:
- UNREACHABLE();
- return static_cast<T>(0);
- }
-}
+T QuerySingleVertexAttributeParameter(const VertexAttribute& attrib, GLenum pname);
size_t ComputeVertexAttributeTypeSize(const VertexAttribute& attrib);
size_t ComputeVertexAttributeStride(const VertexAttribute& attrib);
+size_t ComputeVertexAttributeElementCount(const VertexAttribute &attrib,
+ size_t drawCount,
+ size_t instanceCount);
struct VertexAttribCurrentValueData
{
@@ -79,44 +58,18 @@ struct VertexAttribCurrentValueData
};
GLenum Type;
- void setFloatValues(const GLfloat floatValues[4])
- {
- for (unsigned int valueIndex = 0; valueIndex < 4; valueIndex++)
- {
- FloatValues[valueIndex] = floatValues[valueIndex];
- }
- Type = GL_FLOAT;
- }
-
- void setIntValues(const GLint intValues[4])
- {
- for (unsigned int valueIndex = 0; valueIndex < 4; valueIndex++)
- {
- IntValues[valueIndex] = intValues[valueIndex];
- }
- Type = GL_INT;
- }
-
- void setUnsignedIntValues(const GLuint unsignedIntValues[4])
- {
- for (unsigned int valueIndex = 0; valueIndex < 4; valueIndex++)
- {
- UnsignedIntValues[valueIndex] = unsignedIntValues[valueIndex];
- }
- Type = GL_UNSIGNED_INT;
- }
-
- bool operator==(const VertexAttribCurrentValueData &other)
- {
- return (Type == other.Type && memcmp(FloatValues, other.FloatValues, sizeof(float) * 4) == 0);
- }
+ VertexAttribCurrentValueData();
- bool operator!=(const VertexAttribCurrentValueData &other)
- {
- return !(*this == other);
- }
+ void setFloatValues(const GLfloat floatValues[4]);
+ void setIntValues(const GLint intValues[4]);
+ void setUnsignedIntValues(const GLuint unsignedIntValues[4]);
};
+bool operator==(const VertexAttribCurrentValueData &a, const VertexAttribCurrentValueData &b);
+bool operator!=(const VertexAttribCurrentValueData &a, const VertexAttribCurrentValueData &b);
+
}
+#include "VertexAttribute.inl"
+
#endif // LIBANGLE_VERTEXATTRIBUTE_H_
diff --git a/src/3rdparty/angle/src/libANGLE/VertexAttribute.inl b/src/3rdparty/angle/src/libANGLE/VertexAttribute.inl
new file mode 100644
index 0000000000..0cd31f6762
--- /dev/null
+++ b/src/3rdparty/angle/src/libANGLE/VertexAttribute.inl
@@ -0,0 +1,103 @@
+//
+// 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.
+//
+// VertexAttribute.inl: Inline vertex attribute methods
+//
+
+namespace gl
+{
+
+inline bool operator==(const VertexAttribute &a, const VertexAttribute &b)
+{
+ return a.enabled == b.enabled &&
+ a.type == b.type &&
+ a.size == b.size &&
+ a.normalized == b.normalized &&
+ a.pureInteger == b.pureInteger &&
+ a.stride == b.stride &&
+ a.pointer == b.pointer &&
+ a.buffer.get() == b.buffer.get() &&
+ a.divisor == b.divisor;
+}
+
+inline bool operator!=(const VertexAttribute &a, const VertexAttribute &b)
+{
+ return !(a == b);
+}
+
+template <typename T>
+T QuerySingleVertexAttributeParameter(const VertexAttribute& attrib, GLenum pname)
+{
+ switch (pname)
+ {
+ case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
+ return static_cast<T>(attrib.enabled ? GL_TRUE : GL_FALSE);
+ case GL_VERTEX_ATTRIB_ARRAY_SIZE:
+ return static_cast<T>(attrib.size);
+ case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
+ return static_cast<T>(attrib.stride);
+ case GL_VERTEX_ATTRIB_ARRAY_TYPE:
+ return static_cast<T>(attrib.type);
+ case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
+ return static_cast<T>(attrib.normalized ? GL_TRUE : GL_FALSE);
+ case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
+ return static_cast<T>(attrib.buffer.id());
+ case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
+ return static_cast<T>(attrib.divisor);
+ case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
+ return static_cast<T>(attrib.pureInteger ? GL_TRUE : GL_FALSE);
+ default:
+ UNREACHABLE();
+ return static_cast<T>(0);
+ }
+}
+
+inline VertexAttribCurrentValueData::VertexAttribCurrentValueData()
+ : Type(GL_FLOAT)
+{
+ FloatValues[0] = 0.0f;
+ FloatValues[1] = 0.0f;
+ FloatValues[2] = 0.0f;
+ FloatValues[3] = 1.0f;
+}
+
+inline void VertexAttribCurrentValueData::setFloatValues(const GLfloat floatValues[4])
+{
+ for (unsigned int valueIndex = 0; valueIndex < 4; valueIndex++)
+ {
+ FloatValues[valueIndex] = floatValues[valueIndex];
+ }
+ Type = GL_FLOAT;
+}
+
+inline void VertexAttribCurrentValueData::setIntValues(const GLint intValues[4])
+{
+ for (unsigned int valueIndex = 0; valueIndex < 4; valueIndex++)
+ {
+ IntValues[valueIndex] = intValues[valueIndex];
+ }
+ Type = GL_INT;
+}
+
+inline void VertexAttribCurrentValueData::setUnsignedIntValues(const GLuint unsignedIntValues[4])
+{
+ for (unsigned int valueIndex = 0; valueIndex < 4; valueIndex++)
+ {
+ UnsignedIntValues[valueIndex] = unsignedIntValues[valueIndex];
+ }
+ Type = GL_UNSIGNED_INT;
+}
+
+inline bool operator==(const VertexAttribCurrentValueData &a, const VertexAttribCurrentValueData &b)
+{
+ return (a.Type == b.Type && memcmp(a.FloatValues, b.FloatValues, sizeof(float) * 4) == 0);
+}
+
+inline bool operator!=(const VertexAttribCurrentValueData &a, const VertexAttribCurrentValueData &b)
+{
+ return !(a == b);
+}
+
+}
diff --git a/src/3rdparty/angle/src/libANGLE/angletypes.cpp b/src/3rdparty/angle/src/libANGLE/angletypes.cpp
index 16879f8041..fa5b157906 100644
--- a/src/3rdparty/angle/src/libANGLE/angletypes.cpp
+++ b/src/3rdparty/angle/src/libANGLE/angletypes.cpp
@@ -15,17 +15,28 @@
namespace gl
{
-bool operator==(const Rectangle &a, const Rectangle &b)
+PrimitiveType GetPrimitiveType(GLenum drawMode)
{
- return a.x == b.x &&
- a.y == b.y &&
- a.width == b.width &&
- a.height == b.height;
-}
-
-bool operator!=(const Rectangle &a, const Rectangle &b)
-{
- return !(a == b);
+ switch (drawMode)
+ {
+ case GL_POINTS:
+ return PRIMITIVE_POINTS;
+ case GL_LINES:
+ return PRIMITIVE_LINES;
+ case GL_LINE_STRIP:
+ return PRIMITIVE_LINE_STRIP;
+ case GL_LINE_LOOP:
+ return PRIMITIVE_LINE_LOOP;
+ case GL_TRIANGLES:
+ return PRIMITIVE_TRIANGLES;
+ case GL_TRIANGLE_STRIP:
+ return PRIMITIVE_TRIANGLE_STRIP;
+ case GL_TRIANGLE_FAN:
+ return PRIMITIVE_TRIANGLE_FAN;
+ default:
+ UNREACHABLE();
+ return PRIMITIVE_TYPE_MAX;
+ }
}
SamplerState::SamplerState()
@@ -35,47 +46,30 @@ SamplerState::SamplerState()
wrapT(GL_REPEAT),
wrapR(GL_REPEAT),
maxAnisotropy(1.0f),
- baseLevel(0),
- maxLevel(1000),
minLod(-1000.0f),
maxLod(1000.0f),
compareMode(GL_NONE),
- compareFunc(GL_LEQUAL),
- swizzleRed(GL_RED),
- swizzleGreen(GL_GREEN),
- swizzleBlue(GL_BLUE),
- swizzleAlpha(GL_ALPHA)
-{}
-
-bool SamplerState::swizzleRequired() const
+ compareFunc(GL_LEQUAL)
{
- return swizzleRed != GL_RED || swizzleGreen != GL_GREEN ||
- swizzleBlue != GL_BLUE || swizzleAlpha != GL_ALPHA;
}
-bool SamplerState::operator==(const SamplerState &other) const
+TextureState::TextureState()
+ : swizzleRed(GL_RED),
+ swizzleGreen(GL_GREEN),
+ swizzleBlue(GL_BLUE),
+ swizzleAlpha(GL_ALPHA),
+ samplerState(),
+ baseLevel(0),
+ maxLevel(1000),
+ immutableFormat(false),
+ immutableLevels(0)
{
- return minFilter == other.minFilter &&
- magFilter == other.magFilter &&
- wrapS == other.wrapS &&
- wrapT == other.wrapT &&
- wrapR == other.wrapR &&
- maxAnisotropy == other.maxAnisotropy &&
- baseLevel == other.baseLevel &&
- maxLevel == other.maxLevel &&
- minLod == other.minLod &&
- maxLod == other.maxLod &&
- compareMode == other.compareMode &&
- compareFunc == other.compareFunc &&
- swizzleRed == other.swizzleRed &&
- swizzleGreen == other.swizzleGreen &&
- swizzleBlue == other.swizzleBlue &&
- swizzleAlpha == other.swizzleAlpha;
}
-bool SamplerState::operator!=(const SamplerState &other) const
+bool TextureState::swizzleRequired() const
{
- return !(*this == other);
+ return swizzleRed != GL_RED || swizzleGreen != GL_GREEN ||
+ swizzleBlue != GL_BLUE || swizzleAlpha != GL_ALPHA;
}
static void MinMax(int a, int b, int *minimum, int *maximum)
@@ -128,119 +122,24 @@ bool ClipRectangle(const Rectangle &source, const Rectangle &clip, Rectangle *in
}
}
-VertexFormat::VertexFormat()
- : mType(GL_NONE),
- mNormalized(GL_FALSE),
- mComponents(0),
- mPureInteger(false)
-{}
-
-VertexFormat::VertexFormat(GLenum type, GLboolean normalized, GLuint components, bool pureInteger)
- : mType(type),
- mNormalized(normalized),
- mComponents(components),
- mPureInteger(pureInteger)
-{
- // Float data can not be normalized, so ignore the user setting
- if (mType == GL_FLOAT || mType == GL_HALF_FLOAT || mType == GL_FIXED)
- {
- mNormalized = GL_FALSE;
- }
-}
-
-VertexFormat::VertexFormat(const VertexAttribute &attrib)
- : mType(attrib.type),
- mNormalized(attrib.normalized ? GL_TRUE : GL_FALSE),
- mComponents(attrib.size),
- mPureInteger(attrib.pureInteger)
-{
- // Ensure we aren't initializing a vertex format which should be using
- // the current-value type
- ASSERT(attrib.enabled);
-
- // Float data can not be normalized, so ignore the user setting
- if (mType == GL_FLOAT || mType == GL_HALF_FLOAT || mType == GL_FIXED)
- {
- mNormalized = GL_FALSE;
- }
-}
-
-VertexFormat::VertexFormat(const VertexAttribute &attrib, GLenum currentValueType)
- : mType(attrib.type),
- mNormalized(attrib.normalized ? GL_TRUE : GL_FALSE),
- mComponents(attrib.size),
- mPureInteger(attrib.pureInteger)
-{
- if (!attrib.enabled)
- {
- mType = currentValueType;
- mNormalized = GL_FALSE;
- mComponents = 4;
- mPureInteger = (currentValueType != GL_FLOAT);
- }
-
- // Float data can not be normalized, so ignore the user setting
- if (mType == GL_FLOAT || mType == GL_HALF_FLOAT || mType == GL_FIXED)
- {
- mNormalized = GL_FALSE;
- }
-}
-
-void VertexFormat::GetInputLayout(VertexFormat *inputLayout,
- Program *program,
- const State &state)
-{
- const std::vector<VertexAttribute> &vertexAttributes = state.getVertexArray()->getVertexAttributes();
- for (unsigned int attributeIndex = 0; attributeIndex < vertexAttributes.size(); attributeIndex++)
- {
- int semanticIndex = program->getSemanticIndex(attributeIndex);
-
- if (semanticIndex != -1)
- {
- inputLayout[semanticIndex] = VertexFormat(vertexAttributes[attributeIndex], state.getVertexAttribCurrentValue(attributeIndex).Type);
- }
- }
-}
-
-bool VertexFormat::operator==(const VertexFormat &other) const
+bool Box::operator==(const Box &other) const
{
- return (mType == other.mType &&
- mComponents == other.mComponents &&
- mNormalized == other.mNormalized &&
- mPureInteger == other.mPureInteger );
+ return (x == other.x && y == other.y && z == other.z &&
+ width == other.width && height == other.height && depth == other.depth);
}
-bool VertexFormat::operator!=(const VertexFormat &other) const
+bool Box::operator!=(const Box &other) const
{
return !(*this == other);
}
-bool VertexFormat::operator<(const VertexFormat& other) const
-{
- if (mType != other.mType)
- {
- return mType < other.mType;
- }
- if (mNormalized != other.mNormalized)
- {
- return mNormalized < other.mNormalized;
- }
- if (mComponents != other.mComponents)
- {
- return mComponents < other.mComponents;
- }
- return mPureInteger < other.mPureInteger;
-}
-
-bool Box::operator==(const Box &other) const
+bool operator==(const Extents &lhs, const Extents &rhs)
{
- return (x == other.x && y == other.y && z == other.z &&
- width == other.width && height == other.height && depth == other.depth);
+ return lhs.width == rhs.width && lhs.height == rhs.height && lhs.depth == rhs.depth;
}
-bool Box::operator!=(const Box &other) const
+bool operator!=(const Extents &lhs, const Extents &rhs)
{
- return !(*this == other);
+ return !(lhs == rhs);
}
-
}
diff --git a/src/3rdparty/angle/src/libANGLE/angletypes.h b/src/3rdparty/angle/src/libANGLE/angletypes.h
index e4e08b5512..c29ad06bd2 100644
--- a/src/3rdparty/angle/src/libANGLE/angletypes.h
+++ b/src/3rdparty/angle/src/libANGLE/angletypes.h
@@ -13,7 +13,8 @@
#include "libANGLE/RefCountObject.h"
#include <stdint.h>
-#include <float.h>
+
+#include <bitset>
namespace gl
{
@@ -23,6 +24,20 @@ class Program;
struct VertexAttribute;
struct VertexAttribCurrentValueData;
+enum PrimitiveType
+{
+ PRIMITIVE_POINTS,
+ PRIMITIVE_LINES,
+ PRIMITIVE_LINE_STRIP,
+ PRIMITIVE_LINE_LOOP,
+ PRIMITIVE_TRIANGLES,
+ PRIMITIVE_TRIANGLE_STRIP,
+ PRIMITIVE_TRIANGLE_FAN,
+ PRIMITIVE_TYPE_MAX,
+};
+
+PrimitiveType GetPrimitiveType(GLenum drawMode);
+
enum SamplerType
{
SAMPLER_PIXEL,
@@ -42,19 +57,10 @@ struct Color
};
template <typename T>
-bool operator==(const Color<T> &a, const Color<T> &b)
-{
- return a.red == b.red &&
- a.green == b.green &&
- a.blue == b.blue &&
- a.alpha == b.alpha;
-}
+bool operator==(const Color<T> &a, const Color<T> &b);
template <typename T>
-bool operator!=(const Color<T> &a, const Color<T> &b)
-{
- return !(a == b);
-}
+bool operator!=(const Color<T> &a, const Color<T> &b);
typedef Color<float> ColorF;
typedef Color<int> ColorI;
@@ -62,13 +68,21 @@ typedef Color<unsigned int> ColorUI;
struct Rectangle
{
+ Rectangle() : x(0), y(0), width(0), height(0) {}
+ Rectangle(int x_in, int y_in, int width_in, int height_in)
+ : x(x_in), y(y_in), width(width_in), height(height_in)
+ {
+ }
+
+ int x0() const { return x; }
+ int y0() const { return y; }
+ int x1() const { return x + width; }
+ int y1() const { return y + height; }
+
int x;
int y;
int width;
int height;
-
- Rectangle() : x(0), y(0), width(0), height(0) { }
- Rectangle(int x_in, int y_in, int width_in, int height_in) : x(x_in), y(y_in), width(width_in), height(height_in) { }
};
bool operator==(const Rectangle &a, const Rectangle &b);
@@ -98,6 +112,9 @@ struct Extents
bool empty() const { return (width * height * depth) == 0; }
};
+bool operator==(const Extents &lhs, const Extents &rhs);
+bool operator!=(const Extents &lhs, const Extents &rhs);
+
struct Box
{
int x;
@@ -172,36 +189,58 @@ struct DepthStencilState
GLuint stencilBackWritemask;
};
+// State from Table 6.10 (state per sampler object)
struct SamplerState
{
SamplerState();
GLenum minFilter;
GLenum magFilter;
+
GLenum wrapS;
GLenum wrapT;
GLenum wrapR;
+
+ // From EXT_texture_filter_anisotropic
float maxAnisotropy;
- GLint baseLevel;
- GLint maxLevel;
GLfloat minLod;
GLfloat maxLod;
GLenum compareMode;
GLenum compareFunc;
+};
+
+bool operator==(const SamplerState &a, const SamplerState &b);
+bool operator!=(const SamplerState &a, const SamplerState &b);
+
+// State from Table 6.9 (state per texture object) in the OpenGL ES 3.0.2 spec.
+struct TextureState
+{
+ TextureState();
GLenum swizzleRed;
GLenum swizzleGreen;
GLenum swizzleBlue;
GLenum swizzleAlpha;
- bool swizzleRequired() const;
+ SamplerState samplerState;
+
+ GLuint baseLevel;
+ GLuint maxLevel;
- bool operator==(const SamplerState &other) const;
- bool operator!=(const SamplerState &other) const;
+ bool immutableFormat;
+ GLuint immutableLevels;
+
+ // From GL_ANGLE_texture_usage
+ GLenum usage;
+
+ bool swizzleRequired() const;
};
+bool operator==(const TextureState &a, const TextureState &b);
+bool operator!=(const TextureState &a, const TextureState &b);
+
struct PixelUnpackState
{
BindingPointer<Buffer> pixelBuffer;
@@ -257,54 +296,56 @@ struct PixelPackState
{}
};
-struct VertexFormat
-{
- GLenum mType;
- GLboolean mNormalized;
- GLuint mComponents;
- bool mPureInteger;
-
- VertexFormat();
- VertexFormat(GLenum type, GLboolean normalized, GLuint components, bool pureInteger);
- explicit VertexFormat(const VertexAttribute &attribute);
- VertexFormat(const VertexAttribute &attribute, GLenum currentValueType);
-
- static void GetInputLayout(VertexFormat *inputLayout,
- Program *program,
- const State& currentValues);
-
- bool operator==(const VertexFormat &other) const;
- bool operator!=(const VertexFormat &other) const;
- bool operator<(const VertexFormat& other) const;
-};
+// Used in Program and VertexArray.
+typedef std::bitset<MAX_VERTEX_ATTRIBS> AttributesMask;
+// Use in Program
+typedef std::bitset<IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS> UniformBlockBindingMask;
}
namespace rx
{
-
enum VendorID : uint32_t
{
- VENDOR_ID_AMD = 0x1002,
- VENDOR_ID_INTEL = 0x8086,
- VENDOR_ID_NVIDIA = 0x10DE,
+ VENDOR_ID_UNKNOWN = 0x0,
+ VENDOR_ID_AMD = 0x1002,
+ VENDOR_ID_INTEL = 0x8086,
+ VENDOR_ID_NVIDIA = 0x10DE,
};
+// A macro that determines whether an object has a given runtime type.
+#if defined(__clang__)
+#if __has_feature(cxx_rtti)
+#define ANGLE_HAS_DYNAMIC_CAST 1
+#endif
+#elif !defined(NDEBUG) && (!defined(_MSC_VER) || defined(_CPPRTTI)) && (!defined(__GNUC__) || __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 3) || defined(__GXX_RTTI))
+#define ANGLE_HAS_DYNAMIC_CAST 1
+#endif
+
+#ifdef ANGLE_HAS_DYNAMIC_CAST
+#define ANGLE_HAS_DYNAMIC_TYPE(type, obj) (dynamic_cast<type >(obj) != nullptr)
+#undef ANGLE_HAS_DYNAMIC_CAST
+#else
+#define ANGLE_HAS_DYNAMIC_TYPE(type, obj) (obj != nullptr)
+#endif
+
// Downcast a base implementation object (EG TextureImpl to TextureD3D)
template <typename DestT, typename SrcT>
inline DestT *GetAs(SrcT *src)
{
- ASSERT(HAS_DYNAMIC_TYPE(DestT*, src));
+ ASSERT(ANGLE_HAS_DYNAMIC_TYPE(DestT*, src));
return static_cast<DestT*>(src);
}
template <typename DestT, typename SrcT>
inline const DestT *GetAs(const SrcT *src)
{
- ASSERT(HAS_DYNAMIC_TYPE(const DestT*, src));
+ ASSERT(ANGLE_HAS_DYNAMIC_TYPE(const DestT*, src));
return static_cast<const DestT*>(src);
}
+#undef ANGLE_HAS_DYNAMIC_TYPE
+
// Downcast a GL object to an Impl (EG gl::Texture to rx::TextureD3D)
template <typename DestT, typename SrcT>
inline DestT *GetImplAs(SrcT *src)
@@ -320,4 +361,52 @@ inline const DestT *GetImplAs(const SrcT *src)
}
+#include "angletypes.inl"
+
+namespace angle
+{
+// Zero-based for better array indexing
+enum FramebufferBinding
+{
+ FramebufferBindingRead = 0,
+ FramebufferBindingDraw,
+ FramebufferBindingSingletonMax,
+ FramebufferBindingBoth = FramebufferBindingSingletonMax,
+ FramebufferBindingMax,
+ FramebufferBindingUnknown = FramebufferBindingMax,
+};
+
+inline FramebufferBinding EnumToFramebufferBinding(GLenum enumValue)
+{
+ switch (enumValue)
+ {
+ case GL_READ_FRAMEBUFFER:
+ return FramebufferBindingRead;
+ case GL_DRAW_FRAMEBUFFER:
+ return FramebufferBindingDraw;
+ case GL_FRAMEBUFFER:
+ return FramebufferBindingBoth;
+ default:
+ UNREACHABLE();
+ return FramebufferBindingUnknown;
+ }
+}
+
+inline GLenum FramebufferBindingToEnum(FramebufferBinding binding)
+{
+ switch (binding)
+ {
+ case FramebufferBindingRead:
+ return GL_READ_FRAMEBUFFER;
+ case FramebufferBindingDraw:
+ return GL_DRAW_FRAMEBUFFER;
+ case FramebufferBindingBoth:
+ return GL_FRAMEBUFFER;
+ default:
+ UNREACHABLE();
+ return GL_NONE;
+ }
+}
+}
+
#endif // LIBANGLE_ANGLETYPES_H_
diff --git a/src/3rdparty/angle/src/libANGLE/angletypes.inl b/src/3rdparty/angle/src/libANGLE/angletypes.inl
new file mode 100644
index 0000000000..d51bcaaa78
--- /dev/null
+++ b/src/3rdparty/angle/src/libANGLE/angletypes.inl
@@ -0,0 +1,78 @@
+//
+// Copyright (c) 2012-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.
+//
+
+// angletypes.inl : Inline definitions of some functions from angletypes.h
+
+namespace gl
+{
+
+template <typename T>
+bool operator==(const Color<T> &a, const Color<T> &b)
+{
+ return a.red == b.red &&
+ a.green == b.green &&
+ a.blue == b.blue &&
+ a.alpha == b.alpha;
+}
+
+template <typename T>
+bool operator!=(const Color<T> &a, const Color<T> &b)
+{
+ return !(a == b);
+}
+
+inline bool operator==(const Rectangle &a, const Rectangle &b)
+{
+ return a.x == b.x &&
+ a.y == b.y &&
+ a.width == b.width &&
+ a.height == b.height;
+}
+
+inline bool operator!=(const Rectangle &a, const Rectangle &b)
+{
+ return !(a == b);
+}
+
+inline bool operator==(const SamplerState &a, const SamplerState &b)
+{
+ return a.minFilter == b.minFilter &&
+ a.magFilter == b.magFilter &&
+ a.wrapS == b.wrapS &&
+ a.wrapT == b.wrapT &&
+ a.wrapR == b.wrapR &&
+ a.maxAnisotropy == b.maxAnisotropy &&
+ a.minLod == b.minLod &&
+ a.maxLod == b.maxLod &&
+ a.compareMode == b.compareMode &&
+ a.compareFunc == b.compareFunc;
+}
+
+inline bool operator!=(const SamplerState &a, const SamplerState &b)
+{
+ return !(a == b);
+}
+
+inline bool operator==(const TextureState &a, const TextureState &b)
+{
+ return a.swizzleRed == b.swizzleRed &&
+ a.swizzleGreen == b.swizzleGreen &&
+ a.swizzleBlue == b.swizzleBlue &&
+ a.swizzleAlpha == b.swizzleAlpha &&
+ a.samplerState == b.samplerState &&
+ a.baseLevel == b.baseLevel &&
+ a.maxLevel == b.maxLevel &&
+ a.immutableFormat == b.immutableFormat &&
+ a.immutableLevels == b.immutableLevels &&
+ a.usage == b.usage;
+}
+
+inline bool operator!=(const TextureState &a, const TextureState &b)
+{
+ return !(a == b);
+}
+
+}
diff --git a/src/3rdparty/angle/src/libANGLE/features.h b/src/3rdparty/angle/src/libANGLE/features.h
index fbe013f47d..ecf486dcf7 100644
--- a/src/3rdparty/angle/src/libANGLE/features.h
+++ b/src/3rdparty/angle/src/libANGLE/features.h
@@ -32,9 +32,22 @@
#define ANGLE_PROGRAM_BINARY_LOAD ANGLE_ENABLED
#endif
-// Shader debug info
-#if !defined(ANGLE_SHADER_DEBUG_INFO)
-#define ANGLE_SHADER_DEBUG_INFO ANGLE_DISABLED
+// Append HLSL assembly to shader debug info. Defaults to enabled in Debug and off in Release.
+#if !defined(ANGLE_APPEND_ASSEMBLY_TO_SHADER_DEBUG_INFO)
+#if !defined(NDEBUG)
+#define ANGLE_APPEND_ASSEMBLY_TO_SHADER_DEBUG_INFO ANGLE_ENABLED
+#else
+#define ANGLE_APPEND_ASSEMBLY_TO_SHADER_DEBUG_INFO ANGLE_DISABLED
+#endif // !defined(NDEBUG)
+#endif // !defined(ANGLE_APPEND_ASSEMBLY_TO_SHADER_DEBUG_INFO)
+
+// Program link validation of precisions for uniforms. This feature was
+// requested by developers to allow non-conformant shaders to be used which
+// contain mismatched precisions.
+// ENABLED validate that precision for uniforms match between vertex and fragment shaders
+// DISABLED allow precision for uniforms to differ between vertex and fragment shaders
+#if !defined(ANGLE_PROGRAM_LINK_VALIDATE_UNIFORM_PRECISION)
+#define ANGLE_PROGRAM_LINK_VALIDATE_UNIFORM_PRECISION ANGLE_ENABLED
#endif
#endif // LIBANGLE_FEATURES_H_
diff --git a/src/3rdparty/angle/src/libANGLE/formatutils.cpp b/src/3rdparty/angle/src/libANGLE/formatutils.cpp
index 51e6a5a65d..3a4df126c5 100644
--- a/src/3rdparty/angle/src/libANGLE/formatutils.cpp
+++ b/src/3rdparty/angle/src/libANGLE/formatutils.cpp
@@ -163,11 +163,6 @@ static bool AlwaysSupported(GLuint, const Extensions &)
return true;
}
-static bool UnimplementedSupport(GLuint, const Extensions &)
-{
- return false;
-}
-
static bool NeverSupported(GLuint, const Extensions &)
{
return false;
@@ -217,6 +212,61 @@ static bool RequireExtAndExt(GLuint, const Extensions &extensions)
return extensions.*bool1 && extensions.*bool2;
}
+// Check support for either of two extensions
+template <ExtensionBool bool1, ExtensionBool bool2>
+static bool RequireExtOrExt(GLuint, const Extensions &extensions)
+{
+ return extensions.*bool1 || extensions.*bool2;
+}
+
+// Special function for half float formats with three or four channels.
+static bool HalfFloatSupport(GLuint clientVersion, const Extensions &extensions)
+{
+ return clientVersion >= 3 || extensions.textureHalfFloat;
+}
+
+static bool HalfFloatRenderableSupport(GLuint clientVersion, const Extensions &extensions)
+{
+ return HalfFloatSupport(clientVersion, extensions) && extensions.colorBufferHalfFloat;
+}
+
+// Special function for half float formats with one or two channels.
+static bool HalfFloatSupportRG(GLuint clientVersion, const Extensions &extensions)
+{
+ return clientVersion >= 3 || (extensions.textureHalfFloat && extensions.textureRG);
+}
+
+static bool HalfFloatRenderableSupportRG(GLuint clientVersion, const Extensions &extensions)
+{
+ return HalfFloatSupportRG(clientVersion, extensions) && extensions.colorBufferHalfFloat;
+}
+
+// Special function for float formats with three or four channels.
+static bool FloatSupport(GLuint clientVersion, const Extensions &extensions)
+{
+ return clientVersion >= 3 || extensions.textureFloat;
+}
+
+static bool FloatRenderableSupport(GLuint clientVersion, const Extensions &extensions)
+{
+ // We don't expose colorBufferFloat in ES2, but we silently support rendering to float.
+ return FloatSupport(clientVersion, extensions) &&
+ (extensions.colorBufferFloat || clientVersion == 2);
+}
+
+// Special function for float formats with one or two channels.
+static bool FloatSupportRG(GLuint clientVersion, const Extensions &extensions)
+{
+ return clientVersion >= 3 || (extensions.textureFloat && extensions.textureRG);
+}
+
+static bool FloatRenderableSupportRG(GLuint clientVersion, const Extensions &extensions)
+{
+ // We don't expose colorBufferFloat in ES2, but we silently support rendering to float.
+ return FloatSupportRG(clientVersion, extensions) &&
+ (extensions.colorBufferFloat || clientVersion == 2);
+}
+
InternalFormat::InternalFormat()
: redBits(0),
greenBits(0),
@@ -228,13 +278,13 @@ InternalFormat::InternalFormat()
stencilBits(0),
pixelBytes(0),
componentCount(0),
+ compressed(false),
compressedBlockWidth(0),
compressedBlockHeight(0),
format(GL_NONE),
type(GL_NONE),
componentType(GL_NONE),
colorEncoding(GL_NONE),
- compressed(false),
textureSupport(NeverSupported),
renderSupport(NeverSupported),
filterSupport(NeverSupported)
@@ -346,6 +396,7 @@ static InternalFormatInfoMap BuildInternalFormatInfoMap()
{
InternalFormatInfoMap map;
+ // clang-format off
// From ES 3.0.1 spec, table 3.12
map.insert(InternalFormatInfoPair(GL_NONE, InternalFormat()));
@@ -362,7 +413,7 @@ static InternalFormatInfoMap BuildInternalFormatInfoMap()
map.insert(InternalFormatInfoPair(GL_RGBA8, RGBAFormat( 8, 8, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, false, RequireESOrExt<3, &Extensions::rgb8rgba8>, RequireESOrExt<3, &Extensions::rgb8rgba8>, AlwaysSupported)));
map.insert(InternalFormatInfoPair(GL_RGBA8_SNORM, RGBAFormat( 8, 8, 8, 8, 0, GL_RGBA, GL_BYTE, GL_SIGNED_NORMALIZED, false, RequireES<3>, NeverSupported, AlwaysSupported)));
map.insert(InternalFormatInfoPair(GL_RGB10_A2, RGBAFormat(10, 10, 10, 2, 0, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, GL_UNSIGNED_NORMALIZED, false, RequireES<3>, RequireES<3>, AlwaysSupported)));
- map.insert(InternalFormatInfoPair(GL_RGB10_A2UI, RGBAFormat(10, 10, 10, 2, 0, GL_RGBA_INTEGER, GL_UNSIGNED_INT_2_10_10_10_REV, GL_UNSIGNED_INT, false, RequireES<3>, NeverSupported, NeverSupported)));
+ map.insert(InternalFormatInfoPair(GL_RGB10_A2UI, RGBAFormat(10, 10, 10, 2, 0, GL_RGBA_INTEGER, GL_UNSIGNED_INT_2_10_10_10_REV, GL_UNSIGNED_INT, false, RequireES<3>, RequireES<3>, NeverSupported)));
map.insert(InternalFormatInfoPair(GL_SRGB8, RGBAFormat( 8, 8, 8, 0, 0, GL_RGB, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, true, RequireESOrExt<3, &Extensions::sRGB>, NeverSupported, AlwaysSupported)));
map.insert(InternalFormatInfoPair(GL_SRGB8_ALPHA8, RGBAFormat( 8, 8, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, true, RequireESOrExt<3, &Extensions::sRGB>, RequireESOrExt<3, &Extensions::sRGB>, AlwaysSupported)));
map.insert(InternalFormatInfoPair(GL_R11F_G11F_B10F, RGBAFormat(11, 11, 10, 0, 0, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV, GL_FLOAT, false, RequireES<3>, RequireExt<&Extensions::colorBufferFloat>, AlwaysSupported)));
@@ -397,23 +448,23 @@ static InternalFormatInfoMap BuildInternalFormatInfoMap()
map.insert(InternalFormatInfoPair(GL_BGR5_A1_ANGLEX, RGBAFormat( 5, 5, 5, 1, 0, GL_BGRA_EXT, GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT, GL_UNSIGNED_NORMALIZED, false, RequireExt<&Extensions::textureFormatBGRA8888>, RequireExt<&Extensions::textureFormatBGRA8888>, AlwaysSupported)));
// Floating point renderability and filtering is provided by OES_texture_float and OES_texture_half_float
- // | Internal format | | D |S | Format | Type | Comp | SRGB | Texture supported | Renderable | Filterable |
- // | | | | | | | type | | | | |
- map.insert(InternalFormatInfoPair(GL_R16F, RGBAFormat(16, 0, 0, 0, 0, GL_RED, GL_HALF_FLOAT, GL_FLOAT, false, RequireESOrExtAndExt<3, &Extensions::textureHalfFloat, &Extensions::textureRG>, RequireESOrExtAndExt<3, &Extensions::textureHalfFloat, &Extensions::textureRG>, RequireExt<&Extensions::textureHalfFloatLinear>)));
- map.insert(InternalFormatInfoPair(GL_RG16F, RGBAFormat(16, 16, 0, 0, 0, GL_RG, GL_HALF_FLOAT, GL_FLOAT, false, RequireESOrExtAndExt<3, &Extensions::textureHalfFloat, &Extensions::textureRG>, RequireESOrExtAndExt<3, &Extensions::textureHalfFloat, &Extensions::textureRG>, RequireExt<&Extensions::textureHalfFloatLinear>)));
- map.insert(InternalFormatInfoPair(GL_RGB16F, RGBAFormat(16, 16, 16, 0, 0, GL_RGB, GL_HALF_FLOAT, GL_FLOAT, false, RequireESOrExt<3, &Extensions::textureHalfFloat>, RequireESOrExt<3, &Extensions::textureHalfFloat>, RequireExt<&Extensions::textureHalfFloatLinear>)));
- map.insert(InternalFormatInfoPair(GL_RGBA16F, RGBAFormat(16, 16, 16, 16, 0, GL_RGBA, GL_HALF_FLOAT, GL_FLOAT, false, RequireESOrExt<3, &Extensions::textureHalfFloat>, RequireESOrExt<3, &Extensions::textureHalfFloat>, RequireExt<&Extensions::textureHalfFloatLinear>)));
- map.insert(InternalFormatInfoPair(GL_R32F, RGBAFormat(32, 0, 0, 0, 0, GL_RED, GL_FLOAT, GL_FLOAT, false, RequireESOrExtAndExt<3, &Extensions::textureFloat, &Extensions::textureRG>, RequireESOrExtAndExt<3, &Extensions::textureFloat, &Extensions::textureRG>, RequireExt<&Extensions::textureFloatLinear> )));
- map.insert(InternalFormatInfoPair(GL_RG32F, RGBAFormat(32, 32, 0, 0, 0, GL_RG, GL_FLOAT, GL_FLOAT, false, RequireESOrExtAndExt<3, &Extensions::textureFloat, &Extensions::textureRG>, RequireESOrExtAndExt<3, &Extensions::textureFloat, &Extensions::textureRG>, RequireExt<&Extensions::textureFloatLinear> )));
- map.insert(InternalFormatInfoPair(GL_RGB32F, RGBAFormat(32, 32, 32, 0, 0, GL_RGB, GL_FLOAT, GL_FLOAT, false, RequireESOrExt<3, &Extensions::textureFloat>, RequireESOrExt<3, &Extensions::textureFloat>, RequireExt<&Extensions::textureFloatLinear> )));
- map.insert(InternalFormatInfoPair(GL_RGBA32F, RGBAFormat(32, 32, 32, 32, 0, GL_RGBA, GL_FLOAT, GL_FLOAT, false, RequireESOrExt<3, &Extensions::textureFloat>, RequireESOrExt<3, &Extensions::textureFloat>, RequireExt<&Extensions::textureFloatLinear> )));
+ // | Internal format | | D |S | Format | Type | Comp | SRGB | Texture supported | Renderable | Filterable |
+ // | | | | | | | type | | | | |
+ map.insert(InternalFormatInfoPair(GL_R16F, RGBAFormat(16, 0, 0, 0, 0, GL_RED, GL_HALF_FLOAT, GL_FLOAT, false, HalfFloatSupportRG, HalfFloatRenderableSupportRG, RequireExt<&Extensions::textureHalfFloatLinear>)));
+ map.insert(InternalFormatInfoPair(GL_RG16F, RGBAFormat(16, 16, 0, 0, 0, GL_RG, GL_HALF_FLOAT, GL_FLOAT, false, HalfFloatSupportRG, HalfFloatRenderableSupportRG, RequireExt<&Extensions::textureHalfFloatLinear>)));
+ map.insert(InternalFormatInfoPair(GL_RGB16F, RGBAFormat(16, 16, 16, 0, 0, GL_RGB, GL_HALF_FLOAT, GL_FLOAT, false, HalfFloatSupport, HalfFloatRenderableSupport, RequireExt<&Extensions::textureHalfFloatLinear>)));
+ map.insert(InternalFormatInfoPair(GL_RGBA16F, RGBAFormat(16, 16, 16, 16, 0, GL_RGBA, GL_HALF_FLOAT, GL_FLOAT, false, HalfFloatSupport, HalfFloatRenderableSupport, RequireExt<&Extensions::textureHalfFloatLinear>)));
+ map.insert(InternalFormatInfoPair(GL_R32F, RGBAFormat(32, 0, 0, 0, 0, GL_RED, GL_FLOAT, GL_FLOAT, false, FloatSupportRG, FloatRenderableSupportRG, RequireExt<&Extensions::textureFloatLinear> )));
+ map.insert(InternalFormatInfoPair(GL_RG32F, RGBAFormat(32, 32, 0, 0, 0, GL_RG, GL_FLOAT, GL_FLOAT, false, FloatSupportRG, FloatRenderableSupportRG, RequireExt<&Extensions::textureFloatLinear> )));
+ map.insert(InternalFormatInfoPair(GL_RGB32F, RGBAFormat(32, 32, 32, 0, 0, GL_RGB, GL_FLOAT, GL_FLOAT, false, FloatSupport, FloatRenderableSupport, RequireExt<&Extensions::textureFloatLinear> )));
+ map.insert(InternalFormatInfoPair(GL_RGBA32F, RGBAFormat(32, 32, 32, 32, 0, GL_RGBA, GL_FLOAT, GL_FLOAT, false, FloatSupport, FloatRenderableSupport, RequireExt<&Extensions::textureFloatLinear> )));
// Depth stencil formats
// | Internal format | | D |S | X | Format | Type | Component type | Supported | Renderable | Filterable |
map.insert(InternalFormatInfoPair(GL_DEPTH_COMPONENT16, DepthStencilFormat(16, 0, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, GL_UNSIGNED_NORMALIZED, RequireES<2>, RequireES<2>, RequireESOrExt<3, &Extensions::depthTextures>)));
map.insert(InternalFormatInfoPair(GL_DEPTH_COMPONENT24, DepthStencilFormat(24, 0, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, GL_UNSIGNED_NORMALIZED, RequireES<3>, RequireES<3>, RequireESOrExt<3, &Extensions::depthTextures>)));
map.insert(InternalFormatInfoPair(GL_DEPTH_COMPONENT32F, DepthStencilFormat(32, 0, 0, GL_DEPTH_COMPONENT, GL_FLOAT, GL_FLOAT, RequireES<3>, RequireES<3>, RequireESOrExt<3, &Extensions::depthTextures>)));
- map.insert(InternalFormatInfoPair(GL_DEPTH_COMPONENT32_OES, DepthStencilFormat(32, 0, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, GL_UNSIGNED_NORMALIZED, RequireExt<&Extensions::depthTextures>, RequireExt<&Extensions::depthTextures>, AlwaysSupported )));
+ map.insert(InternalFormatInfoPair(GL_DEPTH_COMPONENT32_OES, DepthStencilFormat(32, 0, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, GL_UNSIGNED_NORMALIZED, RequireExtOrExt<&Extensions::depthTextures, &Extensions::depth32>, RequireExtOrExt<&Extensions::depthTextures, &Extensions::depth32>, AlwaysSupported )));
map.insert(InternalFormatInfoPair(GL_DEPTH24_STENCIL8, DepthStencilFormat(24, 8, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, GL_UNSIGNED_NORMALIZED, RequireESOrExt<3, &Extensions::depthTextures>, RequireESOrExtOrExt<3, &Extensions::depthTextures, &Extensions::packedDepthStencil>, AlwaysSupported )));
map.insert(InternalFormatInfoPair(GL_DEPTH32F_STENCIL8, DepthStencilFormat(32, 8, 24, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, GL_FLOAT, RequireES<3>, RequireES<3>, AlwaysSupported )));
// STENCIL_INDEX8 is special-cased, see around the bottom of the list.
@@ -450,28 +501,63 @@ static InternalFormatInfoMap BuildInternalFormatInfoMap()
map.insert(InternalFormatInfoPair(GL_SRGB_ALPHA_EXT, UnsizedFormat(GL_RGBA, RequireESOrExt<3, &Extensions::sRGB>, RequireESOrExt<3, &Extensions::sRGB>, AlwaysSupported)));
// Compressed formats, From ES 3.0.1 spec, table 3.16
- // | Internal format | |W |H | BS |CC| Format | Type | SRGB | Supported | Renderable | Filterable |
- map.insert(InternalFormatInfoPair(GL_COMPRESSED_R11_EAC, CompressedFormat(4, 4, 64, 1, GL_COMPRESSED_R11_EAC, GL_UNSIGNED_BYTE, false, UnimplementedSupport, UnimplementedSupport, UnimplementedSupport)));
- map.insert(InternalFormatInfoPair(GL_COMPRESSED_SIGNED_R11_EAC, CompressedFormat(4, 4, 64, 1, GL_COMPRESSED_SIGNED_R11_EAC, GL_UNSIGNED_BYTE, false, UnimplementedSupport, UnimplementedSupport, UnimplementedSupport)));
- map.insert(InternalFormatInfoPair(GL_COMPRESSED_RG11_EAC, CompressedFormat(4, 4, 128, 2, GL_COMPRESSED_RG11_EAC, GL_UNSIGNED_BYTE, false, UnimplementedSupport, UnimplementedSupport, UnimplementedSupport)));
- map.insert(InternalFormatInfoPair(GL_COMPRESSED_SIGNED_RG11_EAC, CompressedFormat(4, 4, 128, 2, GL_COMPRESSED_SIGNED_RG11_EAC, GL_UNSIGNED_BYTE, false, UnimplementedSupport, UnimplementedSupport, UnimplementedSupport)));
- map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGB8_ETC2, CompressedFormat(4, 4, 64, 3, GL_COMPRESSED_RGB8_ETC2, GL_UNSIGNED_BYTE, false, UnimplementedSupport, UnimplementedSupport, UnimplementedSupport)));
- map.insert(InternalFormatInfoPair(GL_COMPRESSED_SRGB8_ETC2, CompressedFormat(4, 4, 64, 3, GL_COMPRESSED_SRGB8_ETC2, GL_UNSIGNED_BYTE, true, UnimplementedSupport, UnimplementedSupport, UnimplementedSupport)));
- map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2, CompressedFormat(4, 4, 64, 3, GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL_UNSIGNED_BYTE, false, UnimplementedSupport, UnimplementedSupport, UnimplementedSupport)));
- map.insert(InternalFormatInfoPair(GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, CompressedFormat(4, 4, 64, 3, GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL_UNSIGNED_BYTE, true, UnimplementedSupport, UnimplementedSupport, UnimplementedSupport)));
- map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA8_ETC2_EAC, CompressedFormat(4, 4, 128, 4, GL_COMPRESSED_RGBA8_ETC2_EAC, GL_UNSIGNED_BYTE, false, UnimplementedSupport, UnimplementedSupport, UnimplementedSupport)));
- map.insert(InternalFormatInfoPair(GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC, CompressedFormat(4, 4, 128, 4, GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC, GL_UNSIGNED_BYTE, true, UnimplementedSupport, UnimplementedSupport, UnimplementedSupport)));
+ // | Internal format | |W |H | BS |CC| Format | Type | SRGB | Supported | Renderable | Filterable |
+ map.insert(InternalFormatInfoPair(GL_COMPRESSED_R11_EAC, CompressedFormat(4, 4, 64, 1, GL_COMPRESSED_R11_EAC, GL_UNSIGNED_BYTE, false, RequireES<3>, NeverSupported, AlwaysSupported)));
+ map.insert(InternalFormatInfoPair(GL_COMPRESSED_SIGNED_R11_EAC, CompressedFormat(4, 4, 64, 1, GL_COMPRESSED_SIGNED_R11_EAC, GL_UNSIGNED_BYTE, false, RequireES<3>, NeverSupported, AlwaysSupported)));
+ map.insert(InternalFormatInfoPair(GL_COMPRESSED_RG11_EAC, CompressedFormat(4, 4, 128, 2, GL_COMPRESSED_RG11_EAC, GL_UNSIGNED_BYTE, false, RequireES<3>, NeverSupported, AlwaysSupported)));
+ map.insert(InternalFormatInfoPair(GL_COMPRESSED_SIGNED_RG11_EAC, CompressedFormat(4, 4, 128, 2, GL_COMPRESSED_SIGNED_RG11_EAC, GL_UNSIGNED_BYTE, false, RequireES<3>, NeverSupported, AlwaysSupported)));
+ map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGB8_ETC2, CompressedFormat(4, 4, 64, 3, GL_COMPRESSED_RGB8_ETC2, GL_UNSIGNED_BYTE, false, RequireES<3>, NeverSupported, AlwaysSupported)));
+ map.insert(InternalFormatInfoPair(GL_COMPRESSED_SRGB8_ETC2, CompressedFormat(4, 4, 64, 3, GL_COMPRESSED_SRGB8_ETC2, GL_UNSIGNED_BYTE, true, RequireES<3>, NeverSupported, AlwaysSupported)));
+ map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2, CompressedFormat(4, 4, 64, 3, GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL_UNSIGNED_BYTE, false, RequireES<3>, NeverSupported, AlwaysSupported)));
+ map.insert(InternalFormatInfoPair(GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, CompressedFormat(4, 4, 64, 3, GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL_UNSIGNED_BYTE, true, RequireES<3>, NeverSupported, AlwaysSupported)));
+ map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA8_ETC2_EAC, CompressedFormat(4, 4, 128, 4, GL_COMPRESSED_RGBA8_ETC2_EAC, GL_UNSIGNED_BYTE, false, RequireES<3>, NeverSupported, AlwaysSupported)));
+ map.insert(InternalFormatInfoPair(GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC, CompressedFormat(4, 4, 128, 4, GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC, GL_UNSIGNED_BYTE, true, RequireES<3>, NeverSupported, AlwaysSupported)));
// From GL_EXT_texture_compression_dxt1
- // | Internal format | |W |H | BS |CC| Format | Type | SRGB | Supported | Renderable | Filterable |
- map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGB_S3TC_DXT1_EXT, CompressedFormat(4, 4, 64, 3, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_UNSIGNED_BYTE, false, RequireExt<&Extensions::textureCompressionDXT1>, NeverSupported, AlwaysSupported)));
- map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, CompressedFormat(4, 4, 64, 4, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, GL_UNSIGNED_BYTE, false, RequireExt<&Extensions::textureCompressionDXT1>, NeverSupported, AlwaysSupported)));
+ // | Internal format | |W |H | BS |CC| Format | Type | SRGB | Supported | Renderable | Filterable |
+ map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGB_S3TC_DXT1_EXT, CompressedFormat(4, 4, 64, 3, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_UNSIGNED_BYTE, false, RequireExt<&Extensions::textureCompressionDXT1>, NeverSupported, AlwaysSupported)));
+ map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, CompressedFormat(4, 4, 64, 4, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, GL_UNSIGNED_BYTE, false, RequireExt<&Extensions::textureCompressionDXT1>, NeverSupported, AlwaysSupported)));
// From GL_ANGLE_texture_compression_dxt3
- map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, CompressedFormat(4, 4, 128, 4, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, GL_UNSIGNED_BYTE, false, RequireExt<&Extensions::textureCompressionDXT5>, NeverSupported, AlwaysSupported)));
+ map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, CompressedFormat(4, 4, 128, 4, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, GL_UNSIGNED_BYTE, false, RequireExt<&Extensions::textureCompressionDXT5>, NeverSupported, AlwaysSupported)));
// From GL_ANGLE_texture_compression_dxt5
- map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, CompressedFormat(4, 4, 128, 4, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, GL_UNSIGNED_BYTE, false, RequireExt<&Extensions::textureCompressionDXT5>, NeverSupported, AlwaysSupported)));
+ map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, CompressedFormat(4, 4, 128, 4, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, GL_UNSIGNED_BYTE, false, RequireExt<&Extensions::textureCompressionDXT5>, NeverSupported, AlwaysSupported)));
+
+ // From GL_OES_compressed_ETC1_RGB8_texture
+ map.insert(InternalFormatInfoPair(GL_ETC1_RGB8_OES, CompressedFormat(4, 4, 64, 3, GL_ETC1_RGB8_OES, GL_UNSIGNED_BYTE, false, RequireExt<&Extensions::compressedETC1RGB8Texture>, NeverSupported, AlwaysSupported)));
+
+ // From KHR_texture_compression_astc_hdr
+ // | Internal format | | W | H | BS |CC| Format | Type | SRGB | Supported | Renderable | Filterable |
+ map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA_ASTC_4x4_KHR, CompressedFormat( 4, 4, 128, 4, GL_COMPRESSED_RGBA_ASTC_4x4_KHR, GL_UNSIGNED_BYTE, false, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported)));
+ map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA_ASTC_5x4_KHR, CompressedFormat( 5, 4, 128, 4, GL_COMPRESSED_RGBA_ASTC_5x4_KHR, GL_UNSIGNED_BYTE, false, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported)));
+ map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA_ASTC_5x5_KHR, CompressedFormat( 5, 5, 128, 4, GL_COMPRESSED_RGBA_ASTC_5x5_KHR, GL_UNSIGNED_BYTE, false, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported)));
+ map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA_ASTC_6x5_KHR, CompressedFormat( 6, 5, 128, 4, GL_COMPRESSED_RGBA_ASTC_6x5_KHR, GL_UNSIGNED_BYTE, false, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported)));
+ map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA_ASTC_6x6_KHR, CompressedFormat( 6, 6, 128, 4, GL_COMPRESSED_RGBA_ASTC_6x6_KHR, GL_UNSIGNED_BYTE, false, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported)));
+ map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA_ASTC_8x5_KHR, CompressedFormat( 8, 5, 128, 4, GL_COMPRESSED_RGBA_ASTC_8x5_KHR, GL_UNSIGNED_BYTE, false, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported)));
+ map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA_ASTC_8x6_KHR, CompressedFormat( 8, 6, 128, 4, GL_COMPRESSED_RGBA_ASTC_8x6_KHR, GL_UNSIGNED_BYTE, false, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported)));
+ map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA_ASTC_8x8_KHR, CompressedFormat( 8, 8, 128, 4, GL_COMPRESSED_RGBA_ASTC_8x8_KHR, GL_UNSIGNED_BYTE, false, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported)));
+ map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA_ASTC_10x5_KHR, CompressedFormat(10, 5, 128, 4, GL_COMPRESSED_RGBA_ASTC_10x5_KHR, GL_UNSIGNED_BYTE, false, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported)));
+ map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA_ASTC_10x6_KHR, CompressedFormat(10, 6, 128, 4, GL_COMPRESSED_RGBA_ASTC_10x6_KHR, GL_UNSIGNED_BYTE, false, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported)));
+ map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA_ASTC_10x8_KHR, CompressedFormat(10, 8, 128, 4, GL_COMPRESSED_RGBA_ASTC_10x8_KHR, GL_UNSIGNED_BYTE, false, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported)));
+ map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA_ASTC_10x10_KHR, CompressedFormat(10, 10, 128, 4, GL_COMPRESSED_RGBA_ASTC_10x10_KHR, GL_UNSIGNED_BYTE, false, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported)));
+ map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA_ASTC_12x10_KHR, CompressedFormat(12, 10, 128, 4, GL_COMPRESSED_RGBA_ASTC_12x10_KHR, GL_UNSIGNED_BYTE, false, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported)));
+ map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA_ASTC_12x12_KHR, CompressedFormat(12, 12, 128, 4, GL_COMPRESSED_RGBA_ASTC_12x12_KHR, GL_UNSIGNED_BYTE, false, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported)));
+
+ map.insert(InternalFormatInfoPair(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR, CompressedFormat( 4, 4, 128, 4, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR, GL_UNSIGNED_BYTE, true, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported)));
+ map.insert(InternalFormatInfoPair(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR, CompressedFormat( 5, 4, 128, 4, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR, GL_UNSIGNED_BYTE, true, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported)));
+ map.insert(InternalFormatInfoPair(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR, CompressedFormat( 5, 5, 128, 4, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR, GL_UNSIGNED_BYTE, true, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported)));
+ map.insert(InternalFormatInfoPair(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR, CompressedFormat( 6, 5, 128, 4, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR, GL_UNSIGNED_BYTE, true, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported)));
+ map.insert(InternalFormatInfoPair(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR, CompressedFormat( 6, 6, 128, 4, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR, GL_UNSIGNED_BYTE, true, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported)));
+ map.insert(InternalFormatInfoPair(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR, CompressedFormat( 8, 5, 128, 4, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR, GL_UNSIGNED_BYTE, true, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported)));
+ map.insert(InternalFormatInfoPair(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR, CompressedFormat( 8, 6, 128, 4, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR, GL_UNSIGNED_BYTE, true, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported)));
+ map.insert(InternalFormatInfoPair(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR, CompressedFormat( 8, 8, 128, 4, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR, GL_UNSIGNED_BYTE, true, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported)));
+ map.insert(InternalFormatInfoPair(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR, CompressedFormat(10, 5, 128, 4, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR, GL_UNSIGNED_BYTE, true, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported)));
+ map.insert(InternalFormatInfoPair(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR, CompressedFormat(10, 6, 128, 4, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR, GL_UNSIGNED_BYTE, true, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported)));
+ map.insert(InternalFormatInfoPair(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR, CompressedFormat(10, 8, 128, 4, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR, GL_UNSIGNED_BYTE, true, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported)));
+ map.insert(InternalFormatInfoPair(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR, CompressedFormat(10, 10, 128, 4, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR, GL_UNSIGNED_BYTE, true, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported)));
+ map.insert(InternalFormatInfoPair(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR, CompressedFormat(12, 10, 128, 4, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR, GL_UNSIGNED_BYTE, true, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported)));
+ map.insert(InternalFormatInfoPair(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR, CompressedFormat(12, 12, 128, 4, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR, GL_UNSIGNED_BYTE, true, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported)));
// For STENCIL_INDEX8 we chose a normalized component type for the following reasons:
// - Multisampled buffer are disallowed for non-normalized integer component types and we want to support it for STENCIL_INDEX8
@@ -480,6 +566,11 @@ static InternalFormatInfoMap BuildInternalFormatInfoMap()
// | Internal format | |D |S |X | Format | Type | Component type | Supported | Renderable | Filterable |
map.insert(InternalFormatInfoPair(GL_STENCIL_INDEX8, DepthStencilFormat(0, 8, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, RequireES<2>, RequireES<2>, NeverSupported)));
+ // From GL_ANGLE_lossy_etc_decode
+ map.insert(InternalFormatInfoPair(GL_ETC1_RGB8_LOSSY_DECODE_ANGLE, CompressedFormat(4, 4, 64, 3, GL_ETC1_RGB8_OES, GL_UNSIGNED_BYTE, false, RequireExt<&Extensions::lossyETCDecode>, NeverSupported, AlwaysSupported)));
+
+ // clang-format on
+
return map;
}
@@ -592,9 +683,23 @@ GLuint InternalFormat::computeRowPitch(GLenum formatType, GLsizei width, GLint a
return rx::roundUp(rowBytes, static_cast<GLuint>(alignment));
}
-GLuint InternalFormat::computeDepthPitch(GLenum formatType, GLsizei width, GLsizei height, GLint alignment, GLint rowLength) const
+GLuint InternalFormat::computeDepthPitch(GLenum formatType,
+ GLsizei width,
+ GLsizei height,
+ GLint alignment,
+ GLint rowLength,
+ GLint imageHeight) const
{
- return computeRowPitch(formatType, width, alignment, rowLength) * height;
+ GLuint rows;
+ if (imageHeight > 0)
+ {
+ rows = imageHeight;
+ }
+ else
+ {
+ rows = height;
+ }
+ return computeRowPitch(formatType, width, alignment, rowLength) * rows;
}
GLuint InternalFormat::computeBlockSize(GLenum formatType, GLsizei width, GLsizei height) const
@@ -619,6 +724,15 @@ GLuint InternalFormat::computeBlockSize(GLenum formatType, GLsizei width, GLsize
}
}
+GLuint InternalFormat::computeSkipPixels(GLint rowPitch,
+ GLint depthPitch,
+ GLint skipImages,
+ GLint skipRows,
+ GLint skipPixels) const
+{
+ return skipImages * depthPitch + skipRows * rowPitch + skipPixels * pixelBytes;
+}
+
GLenum GetSizedInternalFormat(GLenum internalFormat, GLenum type)
{
const InternalFormat& formatInfo = GetInternalFormatInfo(internalFormat);
@@ -647,4 +761,796 @@ const FormatSet &GetAllSizedInternalFormats()
return formatSet;
}
+AttributeType GetAttributeType(GLenum enumValue)
+{
+ switch (enumValue)
+ {
+ case GL_FLOAT:
+ return ATTRIBUTE_FLOAT;
+ case GL_FLOAT_VEC2:
+ return ATTRIBUTE_VEC2;
+ case GL_FLOAT_VEC3:
+ return ATTRIBUTE_VEC3;
+ case GL_FLOAT_VEC4:
+ return ATTRIBUTE_VEC4;
+ case GL_INT:
+ return ATTRIBUTE_INT;
+ case GL_INT_VEC2:
+ return ATTRIBUTE_IVEC2;
+ case GL_INT_VEC3:
+ return ATTRIBUTE_IVEC3;
+ case GL_INT_VEC4:
+ return ATTRIBUTE_IVEC4;
+ case GL_UNSIGNED_INT:
+ return ATTRIBUTE_UINT;
+ case GL_UNSIGNED_INT_VEC2:
+ return ATTRIBUTE_UVEC2;
+ case GL_UNSIGNED_INT_VEC3:
+ return ATTRIBUTE_UVEC3;
+ case GL_UNSIGNED_INT_VEC4:
+ return ATTRIBUTE_UVEC4;
+ case GL_FLOAT_MAT2:
+ return ATTRIBUTE_MAT2;
+ case GL_FLOAT_MAT3:
+ return ATTRIBUTE_MAT3;
+ case GL_FLOAT_MAT4:
+ return ATTRIBUTE_MAT4;
+ case GL_FLOAT_MAT2x3:
+ return ATTRIBUTE_MAT2x3;
+ case GL_FLOAT_MAT2x4:
+ return ATTRIBUTE_MAT2x4;
+ case GL_FLOAT_MAT3x2:
+ return ATTRIBUTE_MAT3x2;
+ case GL_FLOAT_MAT3x4:
+ return ATTRIBUTE_MAT3x4;
+ case GL_FLOAT_MAT4x2:
+ return ATTRIBUTE_MAT4x2;
+ case GL_FLOAT_MAT4x3:
+ return ATTRIBUTE_MAT4x3;
+ default:
+ UNREACHABLE();
+ return ATTRIBUTE_FLOAT;
+ }
+}
+
+VertexFormatType GetVertexFormatType(GLenum type, GLboolean normalized, GLuint components, bool pureInteger)
+{
+ switch (type)
+ {
+ case GL_BYTE:
+ switch (components)
+ {
+ case 1:
+ if (pureInteger)
+ return VERTEX_FORMAT_SBYTE1_INT;
+ if (normalized)
+ return VERTEX_FORMAT_SBYTE1_NORM;
+ return VERTEX_FORMAT_SBYTE1;
+ case 2:
+ if (pureInteger)
+ return VERTEX_FORMAT_SBYTE2_INT;
+ if (normalized)
+ return VERTEX_FORMAT_SBYTE2_NORM;
+ return VERTEX_FORMAT_SBYTE2;
+ case 3:
+ if (pureInteger)
+ return VERTEX_FORMAT_SBYTE3_INT;
+ if (normalized)
+ return VERTEX_FORMAT_SBYTE3_NORM;
+ return VERTEX_FORMAT_SBYTE3;
+ case 4:
+ if (pureInteger)
+ return VERTEX_FORMAT_SBYTE4_INT;
+ if (normalized)
+ return VERTEX_FORMAT_SBYTE4_NORM;
+ return VERTEX_FORMAT_SBYTE4;
+ default:
+ UNREACHABLE();
+ break;
+ }
+ case GL_UNSIGNED_BYTE:
+ switch (components)
+ {
+ case 1:
+ if (pureInteger)
+ return VERTEX_FORMAT_UBYTE1_INT;
+ if (normalized)
+ return VERTEX_FORMAT_UBYTE1_NORM;
+ return VERTEX_FORMAT_UBYTE1;
+ case 2:
+ if (pureInteger)
+ return VERTEX_FORMAT_UBYTE2_INT;
+ if (normalized)
+ return VERTEX_FORMAT_UBYTE2_NORM;
+ return VERTEX_FORMAT_UBYTE2;
+ case 3:
+ if (pureInteger)
+ return VERTEX_FORMAT_UBYTE3_INT;
+ if (normalized)
+ return VERTEX_FORMAT_UBYTE3_NORM;
+ return VERTEX_FORMAT_UBYTE3;
+ case 4:
+ if (pureInteger)
+ return VERTEX_FORMAT_UBYTE4_INT;
+ if (normalized)
+ return VERTEX_FORMAT_UBYTE4_NORM;
+ return VERTEX_FORMAT_UBYTE4;
+ default:
+ UNREACHABLE();
+ break;
+ }
+ case GL_SHORT:
+ switch (components)
+ {
+ case 1:
+ if (pureInteger)
+ return VERTEX_FORMAT_SSHORT1_INT;
+ if (normalized)
+ return VERTEX_FORMAT_SSHORT1_NORM;
+ return VERTEX_FORMAT_SSHORT1;
+ case 2:
+ if (pureInteger)
+ return VERTEX_FORMAT_SSHORT2_INT;
+ if (normalized)
+ return VERTEX_FORMAT_SSHORT2_NORM;
+ return VERTEX_FORMAT_SSHORT2;
+ case 3:
+ if (pureInteger)
+ return VERTEX_FORMAT_SSHORT3_INT;
+ if (normalized)
+ return VERTEX_FORMAT_SSHORT3_NORM;
+ return VERTEX_FORMAT_SSHORT3;
+ case 4:
+ if (pureInteger)
+ return VERTEX_FORMAT_SSHORT4_INT;
+ if (normalized)
+ return VERTEX_FORMAT_SSHORT4_NORM;
+ return VERTEX_FORMAT_SSHORT4;
+ default:
+ UNREACHABLE();
+ break;
+ }
+ case GL_UNSIGNED_SHORT:
+ switch (components)
+ {
+ case 1:
+ if (pureInteger)
+ return VERTEX_FORMAT_USHORT1_INT;
+ if (normalized)
+ return VERTEX_FORMAT_USHORT1_NORM;
+ return VERTEX_FORMAT_USHORT1;
+ case 2:
+ if (pureInteger)
+ return VERTEX_FORMAT_USHORT2_INT;
+ if (normalized)
+ return VERTEX_FORMAT_USHORT2_NORM;
+ return VERTEX_FORMAT_USHORT2;
+ case 3:
+ if (pureInteger)
+ return VERTEX_FORMAT_USHORT3_INT;
+ if (normalized)
+ return VERTEX_FORMAT_USHORT3_NORM;
+ return VERTEX_FORMAT_USHORT3;
+ case 4:
+ if (pureInteger)
+ return VERTEX_FORMAT_USHORT4_INT;
+ if (normalized)
+ return VERTEX_FORMAT_USHORT4_NORM;
+ return VERTEX_FORMAT_USHORT4;
+ default:
+ UNREACHABLE();
+ break;
+ }
+ case GL_INT:
+ switch (components)
+ {
+ case 1:
+ if (pureInteger)
+ return VERTEX_FORMAT_SINT1_INT;
+ if (normalized)
+ return VERTEX_FORMAT_SINT1_NORM;
+ return VERTEX_FORMAT_SINT1;
+ case 2:
+ if (pureInteger)
+ return VERTEX_FORMAT_SINT2_INT;
+ if (normalized)
+ return VERTEX_FORMAT_SINT2_NORM;
+ return VERTEX_FORMAT_SINT2;
+ case 3:
+ if (pureInteger)
+ return VERTEX_FORMAT_SINT3_INT;
+ if (normalized)
+ return VERTEX_FORMAT_SINT3_NORM;
+ return VERTEX_FORMAT_SINT3;
+ case 4:
+ if (pureInteger)
+ return VERTEX_FORMAT_SINT4_INT;
+ if (normalized)
+ return VERTEX_FORMAT_SINT4_NORM;
+ return VERTEX_FORMAT_SINT4;
+ default:
+ UNREACHABLE();
+ break;
+ }
+ case GL_UNSIGNED_INT:
+ switch (components)
+ {
+ case 1:
+ if (pureInteger)
+ return VERTEX_FORMAT_UINT1_INT;
+ if (normalized)
+ return VERTEX_FORMAT_UINT1_NORM;
+ return VERTEX_FORMAT_UINT1;
+ case 2:
+ if (pureInteger)
+ return VERTEX_FORMAT_UINT2_INT;
+ if (normalized)
+ return VERTEX_FORMAT_UINT2_NORM;
+ return VERTEX_FORMAT_UINT2;
+ case 3:
+ if (pureInteger)
+ return VERTEX_FORMAT_UINT3_INT;
+ if (normalized)
+ return VERTEX_FORMAT_UINT3_NORM;
+ return VERTEX_FORMAT_UINT3;
+ case 4:
+ if (pureInteger)
+ return VERTEX_FORMAT_UINT4_INT;
+ if (normalized)
+ return VERTEX_FORMAT_UINT4_NORM;
+ return VERTEX_FORMAT_UINT4;
+ default:
+ UNREACHABLE();
+ break;
+ }
+ case GL_FLOAT:
+ switch (components)
+ {
+ case 1:
+ return VERTEX_FORMAT_FLOAT1;
+ case 2:
+ return VERTEX_FORMAT_FLOAT2;
+ case 3:
+ return VERTEX_FORMAT_FLOAT3;
+ case 4:
+ return VERTEX_FORMAT_FLOAT4;
+ default:
+ UNREACHABLE();
+ break;
+ }
+ case GL_HALF_FLOAT:
+ switch (components)
+ {
+ case 1:
+ return VERTEX_FORMAT_HALF1;
+ case 2:
+ return VERTEX_FORMAT_HALF2;
+ case 3:
+ return VERTEX_FORMAT_HALF3;
+ case 4:
+ return VERTEX_FORMAT_HALF4;
+ default:
+ UNREACHABLE();
+ break;
+ }
+ case GL_FIXED:
+ switch (components)
+ {
+ case 1:
+ return VERTEX_FORMAT_FIXED1;
+ case 2:
+ return VERTEX_FORMAT_FIXED2;
+ case 3:
+ return VERTEX_FORMAT_FIXED3;
+ case 4:
+ return VERTEX_FORMAT_FIXED4;
+ default:
+ UNREACHABLE();
+ break;
+ }
+ case GL_INT_2_10_10_10_REV:
+ if (pureInteger)
+ return VERTEX_FORMAT_SINT210_INT;
+ if (normalized)
+ return VERTEX_FORMAT_SINT210_NORM;
+ return VERTEX_FORMAT_SINT210;
+ case GL_UNSIGNED_INT_2_10_10_10_REV:
+ if (pureInteger)
+ return VERTEX_FORMAT_UINT210_INT;
+ if (normalized)
+ return VERTEX_FORMAT_UINT210_NORM;
+ return VERTEX_FORMAT_UINT210;
+ default:
+ UNREACHABLE();
+ break;
+ }
+ return VERTEX_FORMAT_UBYTE1;
+}
+
+VertexFormatType GetVertexFormatType(const VertexAttribute &attrib)
+{
+ return GetVertexFormatType(attrib.type, attrib.normalized, attrib.size, attrib.pureInteger);
+}
+
+VertexFormatType GetVertexFormatType(const VertexAttribute &attrib, GLenum currentValueType)
+{
+ if (!attrib.enabled)
+ {
+ return GetVertexFormatType(currentValueType, GL_FALSE, 4, (currentValueType != GL_FLOAT));
+ }
+ return GetVertexFormatType(attrib);
+}
+
+const VertexFormat &GetVertexFormatFromType(VertexFormatType vertexFormatType)
+{
+ switch (vertexFormatType)
+ {
+ case VERTEX_FORMAT_SBYTE1:
+ {
+ static const VertexFormat format(GL_BYTE, GL_FALSE, 1, false);
+ return format;
+ }
+ case VERTEX_FORMAT_SBYTE1_NORM:
+ {
+ static const VertexFormat format(GL_BYTE, GL_TRUE, 1, false);
+ return format;
+ }
+ case VERTEX_FORMAT_SBYTE2:
+ {
+ static const VertexFormat format(GL_BYTE, GL_FALSE, 2, false);
+ return format;
+ }
+ case VERTEX_FORMAT_SBYTE2_NORM:
+ {
+ static const VertexFormat format(GL_BYTE, GL_TRUE, 2, false);
+ return format;
+ }
+ case VERTEX_FORMAT_SBYTE3:
+ {
+ static const VertexFormat format(GL_BYTE, GL_FALSE, 3, false);
+ return format;
+ }
+ case VERTEX_FORMAT_SBYTE3_NORM:
+ {
+ static const VertexFormat format(GL_BYTE, GL_TRUE, 3, false);
+ return format;
+ }
+ case VERTEX_FORMAT_SBYTE4:
+ {
+ static const VertexFormat format(GL_BYTE, GL_FALSE, 4, false);
+ return format;
+ }
+ case VERTEX_FORMAT_SBYTE4_NORM:
+ {
+ static const VertexFormat format(GL_BYTE, GL_TRUE, 4, false);
+ return format;
+ }
+ case VERTEX_FORMAT_UBYTE1:
+ {
+ static const VertexFormat format(GL_UNSIGNED_BYTE, GL_FALSE, 1, false);
+ return format;
+ }
+ case VERTEX_FORMAT_UBYTE1_NORM:
+ {
+ static const VertexFormat format(GL_UNSIGNED_BYTE, GL_TRUE, 1, false);
+ return format;
+ }
+ case VERTEX_FORMAT_UBYTE2:
+ {
+ static const VertexFormat format(GL_UNSIGNED_BYTE, GL_FALSE, 2, false);
+ return format;
+ }
+ case VERTEX_FORMAT_UBYTE2_NORM:
+ {
+ static const VertexFormat format(GL_UNSIGNED_BYTE, GL_TRUE, 2, false);
+ return format;
+ }
+ case VERTEX_FORMAT_UBYTE3:
+ {
+ static const VertexFormat format(GL_UNSIGNED_BYTE, GL_FALSE, 3, false);
+ return format;
+ }
+ case VERTEX_FORMAT_UBYTE3_NORM:
+ {
+ static const VertexFormat format(GL_UNSIGNED_BYTE, GL_TRUE, 3, false);
+ return format;
+ }
+ case VERTEX_FORMAT_UBYTE4:
+ {
+ static const VertexFormat format(GL_UNSIGNED_BYTE, GL_FALSE, 4, false);
+ return format;
+ }
+ case VERTEX_FORMAT_UBYTE4_NORM:
+ {
+ static const VertexFormat format(GL_UNSIGNED_BYTE, GL_TRUE, 4, false);
+ return format;
+ }
+ case VERTEX_FORMAT_SSHORT1:
+ {
+ static const VertexFormat format(GL_SHORT, GL_FALSE, 1, false);
+ return format;
+ }
+ case VERTEX_FORMAT_SSHORT1_NORM:
+ {
+ static const VertexFormat format(GL_SHORT, GL_TRUE, 1, false);
+ return format;
+ }
+ case VERTEX_FORMAT_SSHORT2:
+ {
+ static const VertexFormat format(GL_SHORT, GL_FALSE, 2, false);
+ return format;
+ }
+ case VERTEX_FORMAT_SSHORT2_NORM:
+ {
+ static const VertexFormat format(GL_SHORT, GL_TRUE, 2, false);
+ return format;
+ }
+ case VERTEX_FORMAT_SSHORT3:
+ {
+ static const VertexFormat format(GL_SHORT, GL_FALSE, 3, false);
+ return format;
+ }
+ case VERTEX_FORMAT_SSHORT3_NORM:
+ {
+ static const VertexFormat format(GL_SHORT, GL_TRUE, 3, false);
+ return format;
+ }
+ case VERTEX_FORMAT_SSHORT4:
+ {
+ static const VertexFormat format(GL_SHORT, GL_FALSE, 4, false);
+ return format;
+ }
+ case VERTEX_FORMAT_SSHORT4_NORM:
+ {
+ static const VertexFormat format(GL_SHORT, GL_TRUE, 4, false);
+ return format;
+ }
+ case VERTEX_FORMAT_USHORT1:
+ {
+ static const VertexFormat format(GL_UNSIGNED_SHORT, GL_FALSE, 1, false);
+ return format;
+ }
+ case VERTEX_FORMAT_USHORT1_NORM:
+ {
+ static const VertexFormat format(GL_UNSIGNED_SHORT, GL_TRUE, 1, false);
+ return format;
+ }
+ case VERTEX_FORMAT_USHORT2:
+ {
+ static const VertexFormat format(GL_UNSIGNED_SHORT, GL_FALSE, 2, false);
+ return format;
+ }
+ case VERTEX_FORMAT_USHORT2_NORM:
+ {
+ static const VertexFormat format(GL_UNSIGNED_SHORT, GL_TRUE, 2, false);
+ return format;
+ }
+ case VERTEX_FORMAT_USHORT3:
+ {
+ static const VertexFormat format(GL_UNSIGNED_SHORT, GL_FALSE, 3, false);
+ return format;
+ }
+ case VERTEX_FORMAT_USHORT3_NORM:
+ {
+ static const VertexFormat format(GL_UNSIGNED_SHORT, GL_TRUE, 3, false);
+ return format;
+ }
+ case VERTEX_FORMAT_USHORT4:
+ {
+ static const VertexFormat format(GL_UNSIGNED_SHORT, GL_FALSE, 4, false);
+ return format;
+ }
+ case VERTEX_FORMAT_USHORT4_NORM:
+ {
+ static const VertexFormat format(GL_UNSIGNED_SHORT, GL_TRUE, 4, false);
+ return format;
+ }
+ case VERTEX_FORMAT_SINT1:
+ {
+ static const VertexFormat format(GL_INT, GL_FALSE, 1, false);
+ return format;
+ }
+ case VERTEX_FORMAT_SINT1_NORM:
+ {
+ static const VertexFormat format(GL_INT, GL_TRUE, 1, false);
+ return format;
+ }
+ case VERTEX_FORMAT_SINT2:
+ {
+ static const VertexFormat format(GL_INT, GL_FALSE, 2, false);
+ return format;
+ }
+ case VERTEX_FORMAT_SINT2_NORM:
+ {
+ static const VertexFormat format(GL_INT, GL_TRUE, 2, false);
+ return format;
+ }
+ case VERTEX_FORMAT_SINT3:
+ {
+ static const VertexFormat format(GL_INT, GL_FALSE, 3, false);
+ return format;
+ }
+ case VERTEX_FORMAT_SINT3_NORM:
+ {
+ static const VertexFormat format(GL_INT, GL_TRUE, 3, false);
+ return format;
+ }
+ case VERTEX_FORMAT_SINT4:
+ {
+ static const VertexFormat format(GL_INT, GL_FALSE, 4, false);
+ return format;
+ }
+ case VERTEX_FORMAT_SINT4_NORM:
+ {
+ static const VertexFormat format(GL_INT, GL_TRUE, 4, false);
+ return format;
+ }
+ case VERTEX_FORMAT_UINT1:
+ {
+ static const VertexFormat format(GL_UNSIGNED_INT, GL_FALSE, 1, false);
+ return format;
+ }
+ case VERTEX_FORMAT_UINT1_NORM:
+ {
+ static const VertexFormat format(GL_UNSIGNED_INT, GL_TRUE, 1, false);
+ return format;
+ }
+ case VERTEX_FORMAT_UINT2:
+ {
+ static const VertexFormat format(GL_UNSIGNED_INT, GL_FALSE, 2, false);
+ return format;
+ }
+ case VERTEX_FORMAT_UINT2_NORM:
+ {
+ static const VertexFormat format(GL_UNSIGNED_INT, GL_TRUE, 2, false);
+ return format;
+ }
+ case VERTEX_FORMAT_UINT3:
+ {
+ static const VertexFormat format(GL_UNSIGNED_INT, GL_FALSE, 3, false);
+ return format;
+ }
+ case VERTEX_FORMAT_UINT3_NORM:
+ {
+ static const VertexFormat format(GL_UNSIGNED_INT, GL_TRUE, 3, false);
+ return format;
+ }
+ case VERTEX_FORMAT_UINT4:
+ {
+ static const VertexFormat format(GL_UNSIGNED_INT, GL_FALSE, 4, false);
+ return format;
+ }
+ case VERTEX_FORMAT_UINT4_NORM:
+ {
+ static const VertexFormat format(GL_UNSIGNED_INT, GL_TRUE, 4, false);
+ return format;
+ }
+ case VERTEX_FORMAT_SBYTE1_INT:
+ {
+ static const VertexFormat format(GL_BYTE, GL_FALSE, 1, true);
+ return format;
+ }
+ case VERTEX_FORMAT_SBYTE2_INT:
+ {
+ static const VertexFormat format(GL_BYTE, GL_FALSE, 2, true);
+ return format;
+ }
+ case VERTEX_FORMAT_SBYTE3_INT:
+ {
+ static const VertexFormat format(GL_BYTE, GL_FALSE, 3, true);
+ return format;
+ }
+ case VERTEX_FORMAT_SBYTE4_INT:
+ {
+ static const VertexFormat format(GL_BYTE, GL_FALSE, 4, true);
+ return format;
+ }
+ case VERTEX_FORMAT_UBYTE1_INT:
+ {
+ static const VertexFormat format(GL_UNSIGNED_BYTE, GL_FALSE, 1, true);
+ return format;
+ }
+ case VERTEX_FORMAT_UBYTE2_INT:
+ {
+ static const VertexFormat format(GL_UNSIGNED_BYTE, GL_FALSE, 2, true);
+ return format;
+ }
+ case VERTEX_FORMAT_UBYTE3_INT:
+ {
+ static const VertexFormat format(GL_UNSIGNED_BYTE, GL_FALSE, 3, true);
+ return format;
+ }
+ case VERTEX_FORMAT_UBYTE4_INT:
+ {
+ static const VertexFormat format(GL_UNSIGNED_BYTE, GL_FALSE, 4, true);
+ return format;
+ }
+ case VERTEX_FORMAT_SSHORT1_INT:
+ {
+ static const VertexFormat format(GL_SHORT, GL_FALSE, 1, true);
+ return format;
+ }
+ case VERTEX_FORMAT_SSHORT2_INT:
+ {
+ static const VertexFormat format(GL_SHORT, GL_FALSE, 2, true);
+ return format;
+ }
+ case VERTEX_FORMAT_SSHORT3_INT:
+ {
+ static const VertexFormat format(GL_SHORT, GL_FALSE, 3, true);
+ return format;
+ }
+ case VERTEX_FORMAT_SSHORT4_INT:
+ {
+ static const VertexFormat format(GL_SHORT, GL_FALSE, 4, true);
+ return format;
+ }
+ case VERTEX_FORMAT_USHORT1_INT:
+ {
+ static const VertexFormat format(GL_UNSIGNED_SHORT, GL_FALSE, 1, true);
+ return format;
+ }
+ case VERTEX_FORMAT_USHORT2_INT:
+ {
+ static const VertexFormat format(GL_UNSIGNED_SHORT, GL_FALSE, 2, true);
+ return format;
+ }
+ case VERTEX_FORMAT_USHORT3_INT:
+ {
+ static const VertexFormat format(GL_UNSIGNED_SHORT, GL_FALSE, 3, true);
+ return format;
+ }
+ case VERTEX_FORMAT_USHORT4_INT:
+ {
+ static const VertexFormat format(GL_UNSIGNED_SHORT, GL_FALSE, 4, true);
+ return format;
+ }
+ case VERTEX_FORMAT_SINT1_INT:
+ {
+ static const VertexFormat format(GL_INT, GL_FALSE, 1, true);
+ return format;
+ }
+ case VERTEX_FORMAT_SINT2_INT:
+ {
+ static const VertexFormat format(GL_INT, GL_FALSE, 2, true);
+ return format;
+ }
+ case VERTEX_FORMAT_SINT3_INT:
+ {
+ static const VertexFormat format(GL_INT, GL_FALSE, 3, true);
+ return format;
+ }
+ case VERTEX_FORMAT_SINT4_INT:
+ {
+ static const VertexFormat format(GL_INT, GL_FALSE, 4, true);
+ return format;
+ }
+ case VERTEX_FORMAT_UINT1_INT:
+ {
+ static const VertexFormat format(GL_UNSIGNED_INT, GL_FALSE, 1, true);
+ return format;
+ }
+ case VERTEX_FORMAT_UINT2_INT:
+ {
+ static const VertexFormat format(GL_UNSIGNED_INT, GL_FALSE, 2, true);
+ return format;
+ }
+ case VERTEX_FORMAT_UINT3_INT:
+ {
+ static const VertexFormat format(GL_UNSIGNED_INT, GL_FALSE, 3, true);
+ return format;
+ }
+ case VERTEX_FORMAT_UINT4_INT:
+ {
+ static const VertexFormat format(GL_UNSIGNED_INT, GL_FALSE, 4, true);
+ return format;
+ }
+ case VERTEX_FORMAT_FIXED1:
+ {
+ static const VertexFormat format(GL_FIXED, GL_FALSE, 1, false);
+ return format;
+ }
+ case VERTEX_FORMAT_FIXED2:
+ {
+ static const VertexFormat format(GL_FIXED, GL_FALSE, 2, false);
+ return format;
+ }
+ case VERTEX_FORMAT_FIXED3:
+ {
+ static const VertexFormat format(GL_FIXED, GL_FALSE, 3, false);
+ return format;
+ }
+ case VERTEX_FORMAT_FIXED4:
+ {
+ static const VertexFormat format(GL_FIXED, GL_FALSE, 4, false);
+ return format;
+ }
+ case VERTEX_FORMAT_HALF1:
+ {
+ static const VertexFormat format(GL_HALF_FLOAT, GL_FALSE, 1, false);
+ return format;
+ }
+ case VERTEX_FORMAT_HALF2:
+ {
+ static const VertexFormat format(GL_HALF_FLOAT, GL_FALSE, 2, false);
+ return format;
+ }
+ case VERTEX_FORMAT_HALF3:
+ {
+ static const VertexFormat format(GL_HALF_FLOAT, GL_FALSE, 3, false);
+ return format;
+ }
+ case VERTEX_FORMAT_HALF4:
+ {
+ static const VertexFormat format(GL_HALF_FLOAT, GL_FALSE, 4, false);
+ return format;
+ }
+ case VERTEX_FORMAT_FLOAT1:
+ {
+ static const VertexFormat format(GL_FLOAT, GL_FALSE, 1, false);
+ return format;
+ }
+ case VERTEX_FORMAT_FLOAT2:
+ {
+ static const VertexFormat format(GL_FLOAT, GL_FALSE, 2, false);
+ return format;
+ }
+ case VERTEX_FORMAT_FLOAT3:
+ {
+ static const VertexFormat format(GL_FLOAT, GL_FALSE, 3, false);
+ return format;
+ }
+ case VERTEX_FORMAT_FLOAT4:
+ {
+ static const VertexFormat format(GL_FLOAT, GL_FALSE, 4, false);
+ return format;
+ }
+ case VERTEX_FORMAT_SINT210:
+ {
+ static const VertexFormat format(GL_INT_2_10_10_10_REV, GL_FALSE, 4, false);
+ return format;
+ }
+ case VERTEX_FORMAT_UINT210:
+ {
+ static const VertexFormat format(GL_UNSIGNED_INT_2_10_10_10_REV, GL_FALSE, 4, false);
+ return format;
+ }
+ case VERTEX_FORMAT_SINT210_NORM:
+ {
+ static const VertexFormat format(GL_INT_2_10_10_10_REV, GL_TRUE, 4, false);
+ return format;
+ }
+ case VERTEX_FORMAT_UINT210_NORM:
+ {
+ static const VertexFormat format(GL_UNSIGNED_INT_2_10_10_10_REV, GL_TRUE, 4, false);
+ return format;
+ }
+ case VERTEX_FORMAT_SINT210_INT:
+ {
+ static const VertexFormat format(GL_INT_2_10_10_10_REV, GL_FALSE, 4, true);
+ return format;
+ }
+ case VERTEX_FORMAT_UINT210_INT:
+ {
+ static const VertexFormat format(GL_UNSIGNED_INT_2_10_10_10_REV, GL_FALSE, 4, true);
+ return format;
+ }
+ default:
+ {
+ static const VertexFormat format(GL_NONE, GL_FALSE, 0, false);
+ return format;
+ }
+ }
+}
+
+VertexFormat::VertexFormat(GLenum typeIn, GLboolean normalizedIn, GLuint componentsIn, bool pureIntegerIn)
+ : type(typeIn),
+ normalized(normalizedIn),
+ components(componentsIn),
+ pureInteger(pureIntegerIn)
+{
+ // float -> !normalized
+ ASSERT(!(type == GL_FLOAT || type == GL_HALF_FLOAT || type == GL_FIXED) || normalized == GL_FALSE);
+}
+
}
diff --git a/src/3rdparty/angle/src/libANGLE/formatutils.h b/src/3rdparty/angle/src/libANGLE/formatutils.h
index 37d4a8f8ef..6863e4ddc4 100644
--- a/src/3rdparty/angle/src/libANGLE/formatutils.h
+++ b/src/3rdparty/angle/src/libANGLE/formatutils.h
@@ -66,8 +66,18 @@ struct InternalFormat
SupportCheckFunction filterSupport;
GLuint computeRowPitch(GLenum formatType, GLsizei width, GLint alignment, GLint rowLength) const;
- GLuint computeDepthPitch(GLenum formatType, GLsizei width, GLsizei height, GLint alignment, GLint rowLength) const;
+ GLuint computeDepthPitch(GLenum formatType,
+ GLsizei width,
+ GLsizei height,
+ GLint alignment,
+ GLint rowLength,
+ GLint imageHeight) const;
GLuint computeBlockSize(GLenum formatType, GLsizei width, GLsizei height) const;
+ GLuint computeSkipPixels(GLint rowPitch,
+ GLint depthPitch,
+ GLint skipImages,
+ GLint skipRows,
+ GLint skipPixels) const;
};
const InternalFormat &GetInternalFormatInfo(GLenum internalFormat);
@@ -76,6 +86,149 @@ GLenum GetSizedInternalFormat(GLenum internalFormat, GLenum type);
typedef std::set<GLenum> FormatSet;
const FormatSet &GetAllSizedInternalFormats();
-}
+// From the ESSL 3.00.4 spec:
+// Vertex shader inputs can only be float, floating-point vectors, matrices, signed and unsigned
+// integers and integer vectors. Vertex shader inputs cannot be arrays or structures.
+
+enum AttributeType
+{
+ ATTRIBUTE_FLOAT,
+ ATTRIBUTE_VEC2,
+ ATTRIBUTE_VEC3,
+ ATTRIBUTE_VEC4,
+ ATTRIBUTE_INT,
+ ATTRIBUTE_IVEC2,
+ ATTRIBUTE_IVEC3,
+ ATTRIBUTE_IVEC4,
+ ATTRIBUTE_UINT,
+ ATTRIBUTE_UVEC2,
+ ATTRIBUTE_UVEC3,
+ ATTRIBUTE_UVEC4,
+ ATTRIBUTE_MAT2,
+ ATTRIBUTE_MAT3,
+ ATTRIBUTE_MAT4,
+ ATTRIBUTE_MAT2x3,
+ ATTRIBUTE_MAT2x4,
+ ATTRIBUTE_MAT3x2,
+ ATTRIBUTE_MAT3x4,
+ ATTRIBUTE_MAT4x2,
+ ATTRIBUTE_MAT4x3,
+};
+
+AttributeType GetAttributeType(GLenum enumValue);
+
+enum VertexFormatType
+{
+ VERTEX_FORMAT_INVALID,
+ VERTEX_FORMAT_SBYTE1,
+ VERTEX_FORMAT_SBYTE1_NORM,
+ VERTEX_FORMAT_SBYTE2,
+ VERTEX_FORMAT_SBYTE2_NORM,
+ VERTEX_FORMAT_SBYTE3,
+ VERTEX_FORMAT_SBYTE3_NORM,
+ VERTEX_FORMAT_SBYTE4,
+ VERTEX_FORMAT_SBYTE4_NORM,
+ VERTEX_FORMAT_UBYTE1,
+ VERTEX_FORMAT_UBYTE1_NORM,
+ VERTEX_FORMAT_UBYTE2,
+ VERTEX_FORMAT_UBYTE2_NORM,
+ VERTEX_FORMAT_UBYTE3,
+ VERTEX_FORMAT_UBYTE3_NORM,
+ VERTEX_FORMAT_UBYTE4,
+ VERTEX_FORMAT_UBYTE4_NORM,
+ VERTEX_FORMAT_SSHORT1,
+ VERTEX_FORMAT_SSHORT1_NORM,
+ VERTEX_FORMAT_SSHORT2,
+ VERTEX_FORMAT_SSHORT2_NORM,
+ VERTEX_FORMAT_SSHORT3,
+ VERTEX_FORMAT_SSHORT3_NORM,
+ VERTEX_FORMAT_SSHORT4,
+ VERTEX_FORMAT_SSHORT4_NORM,
+ VERTEX_FORMAT_USHORT1,
+ VERTEX_FORMAT_USHORT1_NORM,
+ VERTEX_FORMAT_USHORT2,
+ VERTEX_FORMAT_USHORT2_NORM,
+ VERTEX_FORMAT_USHORT3,
+ VERTEX_FORMAT_USHORT3_NORM,
+ VERTEX_FORMAT_USHORT4,
+ VERTEX_FORMAT_USHORT4_NORM,
+ VERTEX_FORMAT_SINT1,
+ VERTEX_FORMAT_SINT1_NORM,
+ VERTEX_FORMAT_SINT2,
+ VERTEX_FORMAT_SINT2_NORM,
+ VERTEX_FORMAT_SINT3,
+ VERTEX_FORMAT_SINT3_NORM,
+ VERTEX_FORMAT_SINT4,
+ VERTEX_FORMAT_SINT4_NORM,
+ VERTEX_FORMAT_UINT1,
+ VERTEX_FORMAT_UINT1_NORM,
+ VERTEX_FORMAT_UINT2,
+ VERTEX_FORMAT_UINT2_NORM,
+ VERTEX_FORMAT_UINT3,
+ VERTEX_FORMAT_UINT3_NORM,
+ VERTEX_FORMAT_UINT4,
+ VERTEX_FORMAT_UINT4_NORM,
+ VERTEX_FORMAT_SBYTE1_INT,
+ VERTEX_FORMAT_SBYTE2_INT,
+ VERTEX_FORMAT_SBYTE3_INT,
+ VERTEX_FORMAT_SBYTE4_INT,
+ VERTEX_FORMAT_UBYTE1_INT,
+ VERTEX_FORMAT_UBYTE2_INT,
+ VERTEX_FORMAT_UBYTE3_INT,
+ VERTEX_FORMAT_UBYTE4_INT,
+ VERTEX_FORMAT_SSHORT1_INT,
+ VERTEX_FORMAT_SSHORT2_INT,
+ VERTEX_FORMAT_SSHORT3_INT,
+ VERTEX_FORMAT_SSHORT4_INT,
+ VERTEX_FORMAT_USHORT1_INT,
+ VERTEX_FORMAT_USHORT2_INT,
+ VERTEX_FORMAT_USHORT3_INT,
+ VERTEX_FORMAT_USHORT4_INT,
+ VERTEX_FORMAT_SINT1_INT,
+ VERTEX_FORMAT_SINT2_INT,
+ VERTEX_FORMAT_SINT3_INT,
+ VERTEX_FORMAT_SINT4_INT,
+ VERTEX_FORMAT_UINT1_INT,
+ VERTEX_FORMAT_UINT2_INT,
+ VERTEX_FORMAT_UINT3_INT,
+ VERTEX_FORMAT_UINT4_INT,
+ VERTEX_FORMAT_FIXED1,
+ VERTEX_FORMAT_FIXED2,
+ VERTEX_FORMAT_FIXED3,
+ VERTEX_FORMAT_FIXED4,
+ VERTEX_FORMAT_HALF1,
+ VERTEX_FORMAT_HALF2,
+ VERTEX_FORMAT_HALF3,
+ VERTEX_FORMAT_HALF4,
+ VERTEX_FORMAT_FLOAT1,
+ VERTEX_FORMAT_FLOAT2,
+ VERTEX_FORMAT_FLOAT3,
+ VERTEX_FORMAT_FLOAT4,
+ VERTEX_FORMAT_SINT210,
+ VERTEX_FORMAT_UINT210,
+ VERTEX_FORMAT_SINT210_NORM,
+ VERTEX_FORMAT_UINT210_NORM,
+ VERTEX_FORMAT_SINT210_INT,
+ VERTEX_FORMAT_UINT210_INT,
+};
+
+typedef std::vector<gl::VertexFormatType> InputLayout;
+
+struct VertexFormat : angle::NonCopyable
+{
+ VertexFormat(GLenum typeIn, GLboolean normalizedIn, GLuint componentsIn, bool pureIntegerIn);
+
+ GLenum type;
+ GLboolean normalized;
+ GLuint components;
+ bool pureInteger;
+};
+
+VertexFormatType GetVertexFormatType(GLenum type, GLboolean normalized, GLuint components, bool pureInteger);
+VertexFormatType GetVertexFormatType(const VertexAttribute &attrib);
+VertexFormatType GetVertexFormatType(const VertexAttribute &attrib, GLenum currentValueType);
+const VertexFormat &GetVertexFormatFromType(VertexFormatType vertexFormatType);
+
+} // namespace gl
#endif // LIBANGLE_FORMATUTILS_H_
diff --git a/src/3rdparty/angle/src/libANGLE/histogram_macros.h b/src/3rdparty/angle/src/libANGLE/histogram_macros.h
new file mode 100644
index 0000000000..d1c952a6bd
--- /dev/null
+++ b/src/3rdparty/angle/src/libANGLE/histogram_macros.h
@@ -0,0 +1,107 @@
+//
+// 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.
+//
+// histogram_macros.h:
+// Helpers for making histograms, to keep consistency with Chromium's
+// histogram_macros.h.
+
+#ifndef LIBANGLE_HISTOGRAM_MACROS_H_
+#define LIBANGLE_HISTOGRAM_MACROS_H_
+
+#include <platform/Platform.h>
+
+#define ANGLE_HISTOGRAM_TIMES(name, sample) ANGLE_HISTOGRAM_CUSTOM_TIMES( \
+ name, sample, 1, 10000, 50)
+
+#define ANGLE_HISTOGRAM_MEDIUM_TIMES(name, sample) ANGLE_HISTOGRAM_CUSTOM_TIMES( \
+ name, sample, 10, 180000, 50)
+
+// Use this macro when times can routinely be much longer than 10 seconds.
+#define ANGLE_HISTOGRAM_LONG_TIMES(name, sample) ANGLE_HISTOGRAM_CUSTOM_TIMES( \
+ name, sample, 1, 3600000, 50)
+
+// Use this macro when times can routinely be much longer than 10 seconds and
+// you want 100 buckets.
+#define ANGLE_HISTOGRAM_LONG_TIMES_100(name, sample) ANGLE_HISTOGRAM_CUSTOM_TIMES( \
+ name, sample, 1, 3600000, 100)
+
+// For folks that need real specific times, use this to select a precise range
+// of times you want plotted, and the number of buckets you want used.
+#define ANGLE_HISTOGRAM_CUSTOM_TIMES(name, sample, min, max, bucket_count) \
+ ANGLE_HISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, bucket_count)
+
+#define ANGLE_HISTOGRAM_COUNTS(name, sample) ANGLE_HISTOGRAM_CUSTOM_COUNTS( \
+ name, sample, 1, 1000000, 50)
+
+#define ANGLE_HISTOGRAM_COUNTS_100(name, sample) \
+ ANGLE_HISTOGRAM_CUSTOM_COUNTS(name, sample, 1, 100, 50)
+
+#define ANGLE_HISTOGRAM_COUNTS_10000(name, sample) \
+ ANGLE_HISTOGRAM_CUSTOM_COUNTS(name, sample, 1, 10000, 50)
+
+#define ANGLE_HISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, bucket_count) \
+ ANGLEPlatformCurrent()->histogramCustomCounts(\
+ name, sample, min, max, bucket_count)
+
+#define ANGLE_HISTOGRAM_PERCENTAGE(name, under_one_hundred) \
+ ANGLE_HISTOGRAM_ENUMERATION(name, under_one_hundred, 101)
+
+#define ANGLE_HISTOGRAM_BOOLEAN(name, sample) \
+ ANGLEPlatformCurrent()->histogramBoolean(name, sample)
+
+#define ANGLE_HISTOGRAM_ENUMERATION(name, sample, boundary_value) \
+ ANGLEPlatformCurrent()->histogramEnumeration(name, sample, boundary_value)
+
+#define ANGLE_HISTOGRAM_MEMORY_KB(name, sample) ANGLE_HISTOGRAM_CUSTOM_COUNTS( \
+ name, sample, 1000, 500000, 50)
+
+#define ANGLE_HISTOGRAM_MEMORY_MB(name, sample) ANGLE_HISTOGRAM_CUSTOM_COUNTS( \
+ name, sample, 1, 1000, 50)
+
+#define ANGLE_HISTOGRAM_SPARSE_SLOWLY(name, sample) \
+ ANGLEPlatformCurrent()->histogramSparse(name, sample)
+
+// Scoped class which logs its time on this earth as a UMA statistic. This is
+// recommended for when you want a histogram which measures the time it takes
+// for a method to execute. This measures up to 10 seconds.
+#define SCOPED_ANGLE_HISTOGRAM_TIMER(name) \
+ SCOPED_ANGLE_HISTOGRAM_TIMER_EXPANDER(name, false, __COUNTER__)
+
+// Similar scoped histogram timer, but this uses ANGLE_HISTOGRAM_LONG_TIMES_100,
+// which measures up to an hour, and uses 100 buckets. This is more expensive
+// to store, so only use if this often takes >10 seconds.
+#define SCOPED_ANGLE_HISTOGRAM_LONG_TIMER(name) \
+ SCOPED_ANGLE_HISTOGRAM_TIMER_EXPANDER(name, true, __COUNTER__)
+
+// This nested macro is necessary to expand __COUNTER__ to an actual value.
+#define SCOPED_ANGLE_HISTOGRAM_TIMER_EXPANDER(name, is_long, key) \
+ SCOPED_ANGLE_HISTOGRAM_TIMER_UNIQUE(name, is_long, key)
+
+#define SCOPED_ANGLE_HISTOGRAM_TIMER_UNIQUE(name, is_long, key) \
+ class ScopedHistogramTimer##key \
+ { \
+ public: \
+ ScopedHistogramTimer##key() : constructed_(ANGLEPlatformCurrent()->currentTime()) {} \
+ ~ScopedHistogramTimer##key() \
+ { \
+ if (constructed_ == 0) \
+ return; \
+ double elapsed = ANGLEPlatformCurrent()->currentTime() - constructed_; \
+ int elapsedMS = static_cast<int>(elapsed * 1000.0); \
+ if (is_long) \
+ { \
+ ANGLE_HISTOGRAM_LONG_TIMES_100(name, elapsedMS); \
+ } \
+ else \
+ { \
+ ANGLE_HISTOGRAM_TIMES(name, elapsedMS); \
+ } \
+ } \
+ \
+ private: \
+ double constructed_; \
+ } scoped_histogram_timer_##key
+
+#endif // BASE_METRICS_HISTOGRAM_MACROS_H_
diff --git a/src/3rdparty/angle/src/libANGLE/queryconversions.cpp b/src/3rdparty/angle/src/libANGLE/queryconversions.cpp
index 460e346eac..3a6059a89c 100644
--- a/src/3rdparty/angle/src/libANGLE/queryconversions.cpp
+++ b/src/3rdparty/angle/src/libANGLE/queryconversions.cpp
@@ -6,41 +6,48 @@
// queryconversions.cpp: Implementation of state query cast conversions
+#include "libANGLE/queryconversions.h"
+
+#include <vector>
+
#include "libANGLE/Context.h"
#include "common/utilities.h"
namespace gl
{
-// Helper class for converting a GL type to a GLenum:
-// We can't use CastStateValueEnum generally, because of GLboolean + GLubyte overlap.
-// We restrict our use to CastStateValue, where it eliminates duplicate parameters.
+namespace
+{
-template <typename GLType>
-struct CastStateValueEnum { static GLenum mEnumForType; };
+GLint64 ExpandFloatToInteger(GLfloat value)
+{
+ return static_cast<GLint64>((static_cast<double>(0xFFFFFFFFULL) * value - 1.0) / 2.0);
+}
-template <> GLenum CastStateValueEnum<GLint>::mEnumForType = GL_INT;
-template <> GLenum CastStateValueEnum<GLuint>::mEnumForType = GL_UNSIGNED_INT;
-template <> GLenum CastStateValueEnum<GLboolean>::mEnumForType = GL_BOOL;
-template <> GLenum CastStateValueEnum<GLint64>::mEnumForType = GL_INT_64_ANGLEX;
-template <> GLenum CastStateValueEnum<GLfloat>::mEnumForType = GL_FLOAT;
+template <typename QueryT>
+QueryT ClampToQueryRange(GLint64 value)
+{
+ const GLint64 min = static_cast<GLint64>(std::numeric_limits<QueryT>::min());
+ const GLint64 max = static_cast<GLint64>(std::numeric_limits<QueryT>::max());
+ return static_cast<QueryT>(clamp(value, min, max));
+}
template <typename QueryT, typename NativeT>
QueryT CastStateValueToInt(GLenum pname, NativeT value)
{
- GLenum queryType = CastStateValueEnum<QueryT>::mEnumForType;
- GLenum nativeType = CastStateValueEnum<NativeT>::mEnumForType;
+ GLenum queryType = GLTypeToGLenum<QueryT>::value;
+ GLenum nativeType = GLTypeToGLenum<NativeT>::value;
if (nativeType == GL_FLOAT)
{
// RGBA color values and DepthRangeF values are converted to integer using Equation 2.4 from Table 4.5
if (pname == GL_DEPTH_RANGE || pname == GL_COLOR_CLEAR_VALUE || pname == GL_DEPTH_CLEAR_VALUE || pname == GL_BLEND_COLOR)
{
- return static_cast<QueryT>((static_cast<GLfloat>(0xFFFFFFFF) * value - 1.0f) / 2.0f);
+ return ClampToQueryRange<QueryT>(ExpandFloatToInteger(static_cast<GLfloat>(value)));
}
else
{
- return gl::iround<QueryT>(value);
+ return gl::iround<QueryT>(static_cast<GLfloat>(value));
}
}
@@ -59,77 +66,80 @@ QueryT CastStateValueToInt(GLenum pname, NativeT value)
template <typename QueryT, typename NativeT>
QueryT CastStateValue(GLenum pname, NativeT value)
{
- GLenum queryType = CastStateValueEnum<QueryT>::mEnumForType;
+ GLenum queryType = GLTypeToGLenum<QueryT>::value;
switch (queryType)
{
- case GL_INT: return CastStateValueToInt<QueryT, NativeT>(pname, value);
- case GL_INT_64_ANGLEX: return CastStateValueToInt<QueryT, NativeT>(pname, value);
- case GL_FLOAT: return static_cast<QueryT>(value);
- case GL_BOOL: return (value == static_cast<NativeT>(0) ? GL_FALSE : GL_TRUE);
- default: UNREACHABLE(); return 0;
+ case GL_INT:
+ return CastStateValueToInt<QueryT, NativeT>(pname, value);
+ case GL_INT_64_ANGLEX:
+ return CastStateValueToInt<QueryT, NativeT>(pname, value);
+ case GL_FLOAT:
+ return static_cast<QueryT>(value);
+ case GL_BOOL:
+ return static_cast<QueryT>(value == static_cast<NativeT>(0) ? GL_FALSE : GL_TRUE);
+ default:
+ UNREACHABLE();
+ return 0;
}
}
+} // anonymous namespace
+
+template <>
+GLenum GLTypeToGLenum<GLint>::value = GL_INT;
+template <>
+GLenum GLTypeToGLenum<GLuint>::value = GL_UNSIGNED_INT;
+template <>
+GLenum GLTypeToGLenum<GLboolean>::value = GL_BOOL;
+template <>
+GLenum GLTypeToGLenum<GLint64>::value = GL_INT_64_ANGLEX;
+template <>
+GLenum GLTypeToGLenum<GLfloat>::value = GL_FLOAT;
+
template <typename QueryT>
void CastStateValues(Context *context, GLenum nativeType, GLenum pname,
unsigned int numParams, QueryT *outParams)
{
if (nativeType == GL_INT)
{
- GLint *intParams = NULL;
- intParams = new GLint[numParams];
-
- context->getIntegerv(pname, intParams);
+ std::vector<GLint> intParams(numParams, 0);
+ context->getIntegerv(pname, intParams.data());
for (unsigned int i = 0; i < numParams; ++i)
{
outParams[i] = CastStateValue<QueryT>(pname, intParams[i]);
}
-
- delete [] intParams;
}
else if (nativeType == GL_BOOL)
{
- GLboolean *boolParams = NULL;
- boolParams = new GLboolean[numParams];
-
- context->getBooleanv(pname, boolParams);
+ std::vector<GLboolean> boolParams(numParams, GL_FALSE);
+ context->getBooleanv(pname, boolParams.data());
for (unsigned int i = 0; i < numParams; ++i)
{
outParams[i] = (boolParams[i] == GL_FALSE ? static_cast<QueryT>(0) : static_cast<QueryT>(1));
}
-
- delete [] boolParams;
}
else if (nativeType == GL_FLOAT)
{
- GLfloat *floatParams = NULL;
- floatParams = new GLfloat[numParams];
-
- context->getFloatv(pname, floatParams);
+ std::vector<GLfloat> floatParams(numParams, 0.0f);
+ context->getFloatv(pname, floatParams.data());
for (unsigned int i = 0; i < numParams; ++i)
{
outParams[i] = CastStateValue<QueryT>(pname, floatParams[i]);
}
-
- delete [] floatParams;
}
else if (nativeType == GL_INT_64_ANGLEX)
{
- GLint64 *int64Params = NULL;
- int64Params = new GLint64[numParams];
-
- context->getInteger64v(pname, int64Params);
+ std::vector<GLint64> int64Params(numParams, 0);
+ context->getInteger64v(pname, int64Params.data());
for (unsigned int i = 0; i < numParams; ++i)
{
outParams[i] = CastStateValue<QueryT>(pname, int64Params[i]);
}
-
- delete [] int64Params;
}
else UNREACHABLE();
}
diff --git a/src/3rdparty/angle/src/libANGLE/queryconversions.h b/src/3rdparty/angle/src/libANGLE/queryconversions.h
index da7047f730..e0fdbe17e0 100644
--- a/src/3rdparty/angle/src/libANGLE/queryconversions.h
+++ b/src/3rdparty/angle/src/libANGLE/queryconversions.h
@@ -6,8 +6,25 @@
// queryconversions.h: Declaration of state query cast conversions
+#ifndef LIBANGLE_QUERY_CONVERSIONS_H_
+#define LIBANGLE_QUERY_CONVERSIONS_H_
+
+#include "angle_gl.h"
+#include "common/angleutils.h"
+
namespace gl
{
+class Context;
+
+// Helper class for converting a GL type to a GLenum:
+// We can't use CastStateValueEnum generally, because of GLboolean + GLubyte overlap.
+// We restrict our use to CastStateValue, where it eliminates duplicate parameters.
+
+template <typename GLType>
+struct GLTypeToGLenum
+{
+ static GLenum value;
+};
// The GL state query API types are: bool, int, uint, float, int64
template <typename QueryT>
@@ -15,3 +32,5 @@ void CastStateValues(Context *context, GLenum nativeType, GLenum pname,
unsigned int numParams, QueryT *outParams);
}
+
+#endif // LIBANGLE_QUERY_CONVERSIONS_H_
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/BufferImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/BufferImpl.h
index 9bc5eaff58..d77f06cf09 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/BufferImpl.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/BufferImpl.h
@@ -10,7 +10,8 @@
#define LIBANGLE_RENDERER_BUFFERIMPL_H_
#include "common/angleutils.h"
-#include "libANGLE/Buffer.h"
+#include "common/mathutil.h"
+#include "libANGLE/Error.h"
#include <stdint.h>
@@ -25,12 +26,15 @@ class BufferImpl : angle::NonCopyable
virtual gl::Error setData(const void* data, size_t size, GLenum usage) = 0;
virtual gl::Error setSubData(const void* data, size_t size, size_t offset) = 0;
virtual gl::Error copySubData(BufferImpl* source, GLintptr sourceOffset, GLintptr destOffset, GLsizeiptr size) = 0;
- virtual gl::Error map(size_t offset, size_t length, GLbitfield access, GLvoid **mapPtr) = 0;
- virtual gl::Error unmap() = 0;
-
- // This method may not have a corresponding GL-backed function. It is necessary
- // for validation, for certain indexed draw calls.
- virtual gl::Error getData(const uint8_t **outData) = 0;
+ virtual gl::Error map(GLenum access, GLvoid **mapPtr) = 0;
+ virtual gl::Error mapRange(size_t offset, size_t length, GLbitfield access, GLvoid **mapPtr) = 0;
+ virtual gl::Error unmap(GLboolean *result) = 0;
+
+ virtual gl::Error getIndexRange(GLenum type,
+ size_t offset,
+ size_t count,
+ bool primitiveRestartEnabled,
+ gl::IndexRange *outRange) = 0;
};
}
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/BufferImpl_mock.h b/src/3rdparty/angle/src/libANGLE/renderer/BufferImpl_mock.h
new file mode 100644
index 0000000000..a6387661ce
--- /dev/null
+++ b/src/3rdparty/angle/src/libANGLE/renderer/BufferImpl_mock.h
@@ -0,0 +1,38 @@
+//
+// 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.
+//
+
+// BufferImpl_mock.h: Defines a mock of the BufferImpl class.
+
+#ifndef LIBANGLE_RENDERER_BUFFERIMPLMOCK_H_
+#define LIBANGLE_RENDERER_BUFFERIMPLMOCK_H_
+
+#include "gmock/gmock.h"
+
+#include "libANGLE/renderer/BufferImpl.h"
+
+namespace rx
+{
+
+class MockBufferImpl : public BufferImpl
+{
+ public:
+ ~MockBufferImpl() { destructor(); }
+
+ MOCK_METHOD3(setData, gl::Error(const void*, size_t, GLenum));
+ MOCK_METHOD3(setSubData, gl::Error(const void*, size_t, size_t));
+ MOCK_METHOD4(copySubData, gl::Error(BufferImpl *, GLintptr, GLintptr, GLsizeiptr));
+ MOCK_METHOD2(map, gl::Error(GLenum, GLvoid **));
+ MOCK_METHOD4(mapRange, gl::Error(size_t, size_t, GLbitfield, GLvoid **));
+ MOCK_METHOD1(unmap, gl::Error(GLboolean *result));
+
+ MOCK_METHOD5(getIndexRange, gl::Error(GLenum, size_t, size_t, bool, gl::IndexRange *));
+
+ MOCK_METHOD0(destructor, void());
+};
+
+}
+
+#endif // LIBANGLE_RENDERER_BUFFERIMPLMOCK_H_
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/CompilerImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/CompilerImpl.h
index ccc78d8c2a..82f1ffe0d3 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/CompilerImpl.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/CompilerImpl.h
@@ -8,6 +8,7 @@
// for the gl::Compiler object.
#include "common/angleutils.h"
+#include "GLSLANG/ShaderLang.h"
#include "libANGLE/Error.h"
#ifndef LIBANGLE_RENDERER_COMPILERIMPL_H_
@@ -23,6 +24,9 @@ class CompilerImpl : angle::NonCopyable
virtual ~CompilerImpl() {}
virtual gl::Error release() = 0;
+
+ // TODO(jmadill): Expose translator built-in resources init method.
+ virtual ShShaderOutput getTranslatorOutputType() const = 0;
};
}
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/DeviceImpl.cpp b/src/3rdparty/angle/src/libANGLE/renderer/DeviceImpl.cpp
new file mode 100644
index 0000000000..6a166236d0
--- /dev/null
+++ b/src/3rdparty/angle/src/libANGLE/renderer/DeviceImpl.cpp
@@ -0,0 +1,22 @@
+//
+// 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.
+//
+
+// DeviceImpl.cpp: Implementation methods of egl::Device
+
+#include "libANGLE/renderer/DeviceImpl.h"
+
+namespace rx
+{
+
+DeviceImpl::DeviceImpl()
+{
+}
+
+DeviceImpl::~DeviceImpl()
+{
+}
+
+}
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/DeviceImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/DeviceImpl.h
new file mode 100644
index 0000000000..550bc1e2d9
--- /dev/null
+++ b/src/3rdparty/angle/src/libANGLE/renderer/DeviceImpl.h
@@ -0,0 +1,37 @@
+//
+// 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.
+//
+
+// DeviceImpl.h: Implementation methods of egl::Device
+
+#ifndef LIBANGLE_RENDERER_DEVICEIMPL_H_
+#define LIBANGLE_RENDERER_DEVICEIMPL_H_
+
+#include "common/angleutils.h"
+#include "libANGLE/Error.h"
+#include "libANGLE/Caps.h"
+
+namespace egl
+{
+class Device;
+}
+
+namespace rx
+{
+class DeviceImpl : angle::NonCopyable
+{
+ public:
+ DeviceImpl();
+ virtual ~DeviceImpl();
+
+ virtual egl::Error getDevice(void **outValue) = 0;
+ virtual EGLint getType() = 0;
+ virtual void generateExtensions(egl::DeviceExtensions *outExtensions) const = 0;
+ virtual bool deviceExternallySourced() = 0;
+};
+
+}
+
+#endif // LIBANGLE_RENDERER_DEVICEIMPL_H_
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/DisplayImpl.cpp b/src/3rdparty/angle/src/libANGLE/renderer/DisplayImpl.cpp
index 7713ee2d6d..8061189f0a 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/DisplayImpl.cpp
+++ b/src/3rdparty/angle/src/libANGLE/renderer/DisplayImpl.cpp
@@ -21,16 +21,13 @@ DisplayImpl::DisplayImpl()
DisplayImpl::~DisplayImpl()
{
- while (!mSurfaceSet.empty())
- {
- destroySurface(*mSurfaceSet.begin());
- }
+ ASSERT(mSurfaceSet.empty());
}
void DisplayImpl::destroySurface(egl::Surface *surface)
{
mSurfaceSet.erase(surface);
- surface->release();
+ surface->onDestroy();
}
const egl::DisplayExtensions &DisplayImpl::getExtensions() const
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/DisplayImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/DisplayImpl.h
index 381fa67f71..9e38f63370 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/DisplayImpl.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/DisplayImpl.h
@@ -24,6 +24,7 @@ class AttributeMap;
class Display;
struct Config;
class Surface;
+class ImageSibling;
}
namespace gl
@@ -34,7 +35,9 @@ class Context;
namespace rx
{
class SurfaceImpl;
+class ImageImpl;
struct ConfigDesc;
+class DeviceImpl;
class DisplayImpl : angle::NonCopyable
{
@@ -45,16 +48,25 @@ class DisplayImpl : angle::NonCopyable
virtual egl::Error initialize(egl::Display *display) = 0;
virtual void terminate() = 0;
- virtual egl::Error createWindowSurface(const egl::Config *configuration, EGLNativeWindowType window, const egl::AttributeMap &attribs,
- SurfaceImpl **outSurface) = 0;
- virtual egl::Error createPbufferSurface(const egl::Config *configuration, const egl::AttributeMap &attribs,
- SurfaceImpl **outSurface) = 0;
- virtual egl::Error createPbufferFromClientBuffer(const egl::Config *configuration, EGLClientBuffer shareHandle,
- const egl::AttributeMap &attribs, SurfaceImpl **outSurface) = 0;
- virtual egl::Error createPixmapSurface(const egl::Config *configuration, NativePixmapType nativePixmap,
- const egl::AttributeMap &attribs, SurfaceImpl **outSurface) = 0;
- virtual egl::Error createContext(const egl::Config *config, const gl::Context *shareContext, const egl::AttributeMap &attribs,
- gl::Context **outContext) = 0;
+ virtual SurfaceImpl *createWindowSurface(const egl::Config *configuration,
+ EGLNativeWindowType window,
+ const egl::AttributeMap &attribs) = 0;
+ virtual SurfaceImpl *createPbufferSurface(const egl::Config *configuration,
+ const egl::AttributeMap &attribs) = 0;
+ virtual SurfaceImpl *createPbufferFromClientBuffer(const egl::Config *configuration,
+ EGLClientBuffer shareHandle,
+ const egl::AttributeMap &attribs) = 0;
+ virtual SurfaceImpl *createPixmapSurface(const egl::Config *configuration,
+ NativePixmapType nativePixmap,
+ const egl::AttributeMap &attribs) = 0;
+
+ virtual ImageImpl *createImage(EGLenum target,
+ egl::ImageSibling *buffer,
+ const egl::AttributeMap &attribs) = 0;
+
+ virtual gl::Context *createContext(const egl::Config *config,
+ const gl::Context *shareContext,
+ const egl::AttributeMap &attribs) = 0;
virtual egl::Error makeCurrent(egl::Surface *drawSurface, egl::Surface *readSurface, gl::Context *context) = 0;
@@ -68,6 +80,13 @@ class DisplayImpl : angle::NonCopyable
virtual std::string getVendorString() const = 0;
+ virtual egl::Error getDevice(DeviceImpl **device) = 0;
+
+ virtual egl::Error waitClient() const = 0;
+ virtual egl::Error waitNative(EGLint engine,
+ egl::Surface *drawSurface,
+ egl::Surface *readSurface) const = 0;
+
const egl::Caps &getCaps() const;
typedef std::set<egl::Surface*> SurfaceSet;
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/FenceNVImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/FenceNVImpl.h
index 3463921d6e..a534914970 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/FenceNVImpl.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/FenceNVImpl.h
@@ -24,9 +24,9 @@ class FenceNVImpl : angle::NonCopyable
FenceNVImpl() { };
virtual ~FenceNVImpl() { };
- virtual gl::Error set() = 0;
- virtual gl::Error test(bool flushCommandBuffer, GLboolean *outFinished) = 0;
- virtual gl::Error finishFence(GLboolean *outFinished) = 0;
+ virtual gl::Error set(GLenum condition) = 0;
+ virtual gl::Error test(GLboolean *outFinished) = 0;
+ virtual gl::Error finish() = 0;
};
}
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/FenceSyncImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/FenceSyncImpl.h
index 321964113f..6b78e69d47 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/FenceSyncImpl.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/FenceSyncImpl.h
@@ -24,7 +24,7 @@ class FenceSyncImpl : angle::NonCopyable
FenceSyncImpl() { };
virtual ~FenceSyncImpl() { };
- virtual gl::Error set() = 0;
+ virtual gl::Error set(GLenum condition, GLbitfield flags) = 0;
virtual gl::Error clientWait(GLbitfield flags, GLuint64 timeout, GLenum *outResult) = 0;
virtual gl::Error serverWait(GLbitfield flags, GLuint64 timeout) = 0;
virtual gl::Error getStatus(GLint *outResult) = 0;
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/FramebufferImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/FramebufferImpl.h
index 728f949a0f..680122d0ed 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/FramebufferImpl.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/FramebufferImpl.h
@@ -31,22 +31,28 @@ class FramebufferImpl : angle::NonCopyable
explicit FramebufferImpl(const gl::Framebuffer::Data &data) : mData(data) { }
virtual ~FramebufferImpl() { }
- virtual void setColorAttachment(size_t index, const gl::FramebufferAttachment *attachment) = 0;
- virtual void setDepthAttachment(const gl::FramebufferAttachment *attachment) = 0;
- virtual void setStencilAttachment(const gl::FramebufferAttachment *attachment) = 0;
- virtual void setDepthStencilAttachment(const gl::FramebufferAttachment *attachment) = 0;
-
- virtual void setDrawBuffers(size_t count, const GLenum *buffers) = 0;
- virtual void setReadBuffer(GLenum buffer) = 0;
-
+ virtual gl::Error discard(size_t count, const GLenum *attachments) = 0;
virtual gl::Error invalidate(size_t count, const GLenum *attachments) = 0;
virtual gl::Error invalidateSub(size_t count, const GLenum *attachments, const gl::Rectangle &area) = 0;
virtual gl::Error clear(const gl::Data &data, GLbitfield mask) = 0;
- virtual gl::Error clearBufferfv(const gl::State &state, GLenum buffer, GLint drawbuffer, const GLfloat *values) = 0;
- virtual gl::Error clearBufferuiv(const gl::State &state, GLenum buffer, GLint drawbuffer, const GLuint *values) = 0;
- virtual gl::Error clearBufferiv(const gl::State &state, GLenum buffer, GLint drawbuffer, const GLint *values) = 0;
- virtual gl::Error clearBufferfi(const gl::State &state, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) = 0;
+ virtual gl::Error clearBufferfv(const gl::Data &data,
+ GLenum buffer,
+ GLint drawbuffer,
+ const GLfloat *values) = 0;
+ virtual gl::Error clearBufferuiv(const gl::Data &data,
+ GLenum buffer,
+ GLint drawbuffer,
+ const GLuint *values) = 0;
+ virtual gl::Error clearBufferiv(const gl::Data &data,
+ GLenum buffer,
+ GLint drawbuffer,
+ const GLint *values) = 0;
+ virtual gl::Error clearBufferfi(const gl::Data &data,
+ GLenum buffer,
+ GLint drawbuffer,
+ GLfloat depth,
+ GLint stencil) = 0;
virtual GLenum getImplementationColorReadFormat() const = 0;
virtual GLenum getImplementationColorReadType() const = 0;
@@ -55,7 +61,9 @@ class FramebufferImpl : angle::NonCopyable
virtual gl::Error blit(const gl::State &state, const gl::Rectangle &sourceArea, const gl::Rectangle &destArea,
GLbitfield mask, GLenum filter, const gl::Framebuffer *sourceFramebuffer) = 0;
- virtual GLenum checkStatus() const = 0;
+ virtual bool checkStatus() const = 0;
+
+ virtual void syncState(const gl::Framebuffer::DirtyBits &dirtyBits) = 0;
const gl::Framebuffer::Data &getData() const { return mData; }
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/FramebufferImpl_mock.h b/src/3rdparty/angle/src/libANGLE/renderer/FramebufferImpl_mock.h
new file mode 100644
index 0000000000..57c95342d7
--- /dev/null
+++ b/src/3rdparty/angle/src/libANGLE/renderer/FramebufferImpl_mock.h
@@ -0,0 +1,72 @@
+//
+// 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.
+//
+// FramebufferImpl_mock.h:
+// Defines a mock of the FramebufferImpl class.
+//
+
+#ifndef LIBANGLE_RENDERER_FRAMEBUFFERIMPLMOCK_H_
+#define LIBANGLE_RENDERER_FRAMEBUFFERIMPLMOCK_H_
+
+#include "gmock/gmock.h"
+
+#include "libANGLE/renderer/FramebufferImpl.h"
+
+namespace rx
+{
+
+class MockFramebufferImpl : public rx::FramebufferImpl
+{
+ public:
+ MockFramebufferImpl() : rx::FramebufferImpl(gl::Framebuffer::Data()) {}
+ virtual ~MockFramebufferImpl() { destroy(); }
+
+ MOCK_METHOD2(discard, gl::Error(size_t, const GLenum *));
+ MOCK_METHOD2(invalidate, gl::Error(size_t, const GLenum *));
+ MOCK_METHOD3(invalidateSub, gl::Error(size_t, const GLenum *, const gl::Rectangle &));
+
+ MOCK_METHOD2(clear, gl::Error(const gl::Data &, GLbitfield));
+ MOCK_METHOD4(clearBufferfv, gl::Error(const gl::Data &, GLenum, GLint, const GLfloat *));
+ MOCK_METHOD4(clearBufferuiv, gl::Error(const gl::Data &, GLenum, GLint, const GLuint *));
+ MOCK_METHOD4(clearBufferiv, gl::Error(const gl::Data &, GLenum, GLint, const GLint *));
+ MOCK_METHOD5(clearBufferfi, gl::Error(const gl::Data &, GLenum, GLint, GLfloat, GLint));
+
+ MOCK_CONST_METHOD0(getImplementationColorReadFormat, GLenum());
+ MOCK_CONST_METHOD0(getImplementationColorReadType, GLenum());
+ MOCK_CONST_METHOD5(
+ readPixels,
+ gl::Error(const gl::State &, const gl::Rectangle &, GLenum, GLenum, GLvoid *));
+
+ MOCK_METHOD6(blit,
+ gl::Error(const gl::State &,
+ const gl::Rectangle &,
+ const gl::Rectangle &,
+ GLbitfield,
+ GLenum,
+ const gl::Framebuffer *));
+
+ MOCK_CONST_METHOD0(checkStatus, bool());
+
+ MOCK_METHOD1(syncState, void(const gl::Framebuffer::DirtyBits &));
+
+ MOCK_METHOD0(destroy, void());
+};
+
+inline ::testing::NiceMock<MockFramebufferImpl> *MakeFramebufferMock()
+{
+ ::testing::NiceMock<MockFramebufferImpl> *framebufferImpl =
+ new ::testing::NiceMock<MockFramebufferImpl>();
+ // TODO(jmadill): add ON_CALLS for other returning methods
+ ON_CALL(*framebufferImpl, checkStatus()).WillByDefault(::testing::Return(true));
+
+ // We must mock the destructor since NiceMock doesn't work for destructors.
+ EXPECT_CALL(*framebufferImpl, destroy()).Times(1).RetiresOnSaturation();
+
+ return framebufferImpl;
+}
+
+} // namespace rx
+
+#endif // LIBANGLE_RENDERER_FRAMEBUFFERIMPLMOCK_H_
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/ImageImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/ImageImpl.h
new file mode 100644
index 0000000000..e48f1946a8
--- /dev/null
+++ b/src/3rdparty/angle/src/libANGLE/renderer/ImageImpl.h
@@ -0,0 +1,32 @@
+//
+// 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.
+//
+
+// ImageImpl.h: Defines the rx::ImageImpl class representing the EGLimage object.
+
+#ifndef LIBANGLE_RENDERER_IMAGEIMPL_H_
+#define LIBANGLE_RENDERER_IMAGEIMPL_H_
+
+#include "common/angleutils.h"
+#include "libANGLE/Error.h"
+
+namespace egl
+{
+class ImageSibling;
+}
+
+namespace rx
+{
+class ImageImpl : angle::NonCopyable
+{
+ public:
+ virtual ~ImageImpl() {}
+ virtual egl::Error initialize() = 0;
+
+ virtual gl::Error orphan(egl::ImageSibling *sibling) = 0;
+};
+}
+
+#endif // LIBANGLE_RENDERER_IMAGEIMPL_H_
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/ImageImpl_mock.h b/src/3rdparty/angle/src/libANGLE/renderer/ImageImpl_mock.h
new file mode 100644
index 0000000000..27fe6a3947
--- /dev/null
+++ b/src/3rdparty/angle/src/libANGLE/renderer/ImageImpl_mock.h
@@ -0,0 +1,28 @@
+//
+// 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.
+//
+
+// ImageImpl_mock.h: Defines a mock of the ImageImpl class.
+
+#ifndef LIBANGLE_RENDERER_IMAGEIMPLMOCK_H_
+#define LIBANGLE_RENDERER_IMAGEIMPLMOCK_H_
+
+#include "gmock/gmock.h"
+
+#include "libANGLE/renderer/ImageImpl.h"
+
+namespace rx
+{
+class MockImageImpl : public ImageImpl
+{
+ public:
+ virtual ~MockImageImpl() { destructor(); }
+ MOCK_METHOD0(initialize, egl::Error(void));
+ MOCK_METHOD1(orphan, gl::Error(egl::ImageSibling *));
+ MOCK_METHOD0(destructor, void());
+};
+}
+
+#endif // LIBANGLE_RENDERER_IMAGEIMPLMOCK_H_
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/ImplFactory.h b/src/3rdparty/angle/src/libANGLE/renderer/ImplFactory.h
index d77e59f7df..b988fcf97f 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/ImplFactory.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/ImplFactory.h
@@ -11,6 +11,9 @@
#define LIBANGLE_RENDERER_IMPLFACTORY_H_
#include "libANGLE/Framebuffer.h"
+#include "libANGLE/Program.h"
+#include "libANGLE/Shader.h"
+#include "libANGLE/VertexArray.h"
namespace rx
{
@@ -22,6 +25,7 @@ class FramebufferImpl;
class ProgramImpl;
class QueryImpl;
class RenderbufferImpl;
+class SamplerImpl;
class ShaderImpl;
class TextureImpl;
class TransformFeedbackImpl;
@@ -34,12 +38,11 @@ class ImplFactory : angle::NonCopyable
virtual ~ImplFactory() {}
// Shader creation
- virtual CompilerImpl *createCompiler(const gl::Data &data) = 0;
- virtual ShaderImpl *createShader(GLenum type) = 0;
- virtual ProgramImpl *createProgram() = 0;
+ virtual CompilerImpl *createCompiler() = 0;
+ virtual ShaderImpl *createShader(const gl::Shader::Data &data) = 0;
+ virtual ProgramImpl *createProgram(const gl::Program::Data &data) = 0;
// Framebuffer creation
- virtual FramebufferImpl *createDefaultFramebuffer(const gl::Framebuffer::Data &data) = 0;
virtual FramebufferImpl *createFramebuffer(const gl::Framebuffer::Data &data) = 0;
// Texture creation
@@ -52,7 +55,7 @@ class ImplFactory : angle::NonCopyable
virtual BufferImpl *createBuffer() = 0;
// Vertex Array creation
- virtual VertexArrayImpl *createVertexArray() = 0;
+ virtual VertexArrayImpl *createVertexArray(const gl::VertexArray::Data &data) = 0;
// Query and Fence creation
virtual QueryImpl *createQuery(GLenum type) = 0;
@@ -61,6 +64,9 @@ class ImplFactory : angle::NonCopyable
// Transform Feedback creation
virtual TransformFeedbackImpl *createTransformFeedback() = 0;
+
+ // Sampler object creation
+ virtual SamplerImpl *createSampler() = 0;
};
}
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/IndexRangeCache.cpp b/src/3rdparty/angle/src/libANGLE/renderer/IndexRangeCache.cpp
deleted file mode 100644
index 4a71cf4b45..0000000000
--- a/src/3rdparty/angle/src/libANGLE/renderer/IndexRangeCache.cpp
+++ /dev/null
@@ -1,114 +0,0 @@
-//
-// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-//
-
-// IndexRangeCache.cpp: Defines the rx::IndexRangeCache class which stores information about
-// ranges of indices.
-
-#include "libANGLE/renderer/IndexRangeCache.h"
-#include "libANGLE/formatutils.h"
-
-#include "common/debug.h"
-
-namespace rx
-{
-
-template <class IndexType>
-static RangeUI ComputeTypedRange(const IndexType *indices, GLsizei count)
-{
- unsigned int minIndex = indices[0];
- unsigned int maxIndex = indices[0];
-
- for (GLsizei i = 1; i < count; i++)
- {
- if (minIndex > indices[i]) minIndex = indices[i];
- if (maxIndex < indices[i]) maxIndex = indices[i];
- }
-
- return RangeUI(minIndex, maxIndex);
-}
-
-RangeUI IndexRangeCache::ComputeRange(GLenum type, const GLvoid *indices, GLsizei count)
-{
- switch (type)
- {
- case GL_UNSIGNED_BYTE:
- return ComputeTypedRange(static_cast<const GLubyte*>(indices), count);
- case GL_UNSIGNED_INT:
- return ComputeTypedRange(static_cast<const GLuint*>(indices), count);
- case GL_UNSIGNED_SHORT:
- return ComputeTypedRange(static_cast<const GLushort*>(indices), count);
- default:
- UNREACHABLE();
- return RangeUI();
- }
-}
-
-void IndexRangeCache::addRange(GLenum type, unsigned int offset, GLsizei count, const RangeUI &range)
-{
- mIndexRangeCache[IndexRange(type, offset, count)] = range;
-}
-
-void IndexRangeCache::invalidateRange(unsigned int offset, unsigned int size)
-{
- unsigned int invalidateStart = offset;
- unsigned int invalidateEnd = offset + size;
-
- IndexRangeMap::iterator i = mIndexRangeCache.begin();
- while (i != mIndexRangeCache.end())
- {
- unsigned int rangeStart = i->first.offset;
- unsigned int rangeEnd = i->first.offset + (gl::GetTypeInfo(i->first.type).bytes * i->first.count);
-
- if (invalidateEnd < rangeStart || invalidateStart > rangeEnd)
- {
- ++i;
- }
- else
- {
- mIndexRangeCache.erase(i++);
- }
- }
-}
-
-bool IndexRangeCache::findRange(GLenum type, unsigned int offset, GLsizei count,
- RangeUI *outRange) const
-{
- IndexRangeMap::const_iterator i = mIndexRangeCache.find(IndexRange(type, offset, count));
- if (i != mIndexRangeCache.end())
- {
- if (outRange) *outRange = i->second;
- return true;
- }
- else
- {
- if (outRange) *outRange = RangeUI(0, 0);
- return false;
- }
-}
-
-void IndexRangeCache::clear()
-{
- mIndexRangeCache.clear();
-}
-
-IndexRangeCache::IndexRange::IndexRange()
- : type(GL_NONE), offset(0), count(0)
-{
-}
-
-IndexRangeCache::IndexRange::IndexRange(GLenum typ, intptr_t off, GLsizei c)
- : type(typ), offset(off), count(c)
-{
-}
-
-bool IndexRangeCache::IndexRange::operator<(const IndexRange& rhs) const
-{
- if (type != rhs.type) return type < rhs.type;
- if (offset != rhs.offset) return offset < rhs.offset;
- return count < rhs.count;
-}
-
-}
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/IndexRangeCache.h b/src/3rdparty/angle/src/libANGLE/renderer/IndexRangeCache.h
deleted file mode 100644
index 77249f5ff6..0000000000
--- a/src/3rdparty/angle/src/libANGLE/renderer/IndexRangeCache.h
+++ /dev/null
@@ -1,53 +0,0 @@
-//
-// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-//
-
-// IndexRangeCache.h: Defines the rx::IndexRangeCache class which stores information about
-// ranges of indices.
-
-#ifndef LIBANGLE_RENDERER_INDEXRANGECACHE_H_
-#define LIBANGLE_RENDERER_INDEXRANGECACHE_H_
-
-#include "common/angleutils.h"
-#include "common/mathutil.h"
-
-#include "angle_gl.h"
-
-#include <map>
-
-namespace rx
-{
-
-class IndexRangeCache
-{
- public:
- void addRange(GLenum type, unsigned int offset, GLsizei count, const RangeUI &range);
- bool findRange(GLenum type, unsigned int offset, GLsizei count, RangeUI *rangeOut) const;
-
- void invalidateRange(unsigned int offset, unsigned int size);
- void clear();
-
- static RangeUI ComputeRange(GLenum type, const GLvoid *indices, GLsizei count);
-
- private:
- struct IndexRange
- {
- GLenum type;
- unsigned int offset;
- GLsizei count;
-
- IndexRange();
- IndexRange(GLenum type, intptr_t offset, GLsizei count);
-
- bool operator<(const IndexRange& rhs) const;
- };
-
- typedef std::map<IndexRange, RangeUI> IndexRangeMap;
- IndexRangeMap mIndexRangeCache;
-};
-
-}
-
-#endif // LIBANGLE_RENDERER_INDEXRANGECACHE_H_
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/ProgramImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/ProgramImpl.h
index 1128ab6741..1e688045a1 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/ProgramImpl.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/ProgramImpl.h
@@ -23,33 +23,24 @@ namespace rx
struct LinkResult
{
+ LinkResult(bool linkSuccess, const gl::Error &error) : linkSuccess(linkSuccess), error(error) {}
+
bool linkSuccess;
gl::Error error;
- LinkResult(bool linkSuccess, const gl::Error &error);
};
class ProgramImpl : angle::NonCopyable
{
public:
- typedef int SemanticIndexArray[gl::MAX_VERTEX_ATTRIBS];
-
- ProgramImpl() { }
- virtual ~ProgramImpl();
-
- virtual bool usesPointSize() const = 0;
- virtual int getShaderVersion() const = 0;
- virtual GLenum getTransformFeedbackBufferMode() const = 0;
+ ProgramImpl(const gl::Program::Data &data) : mData(data) {}
+ virtual ~ProgramImpl() {}
- virtual GLenum getBinaryFormat() = 0;
virtual LinkResult load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream) = 0;
virtual gl::Error save(gl::BinaryOutputStream *stream) = 0;
+ virtual void setBinaryRetrievableHint(bool retrievable) = 0;
- virtual LinkResult link(const gl::Data &data, gl::InfoLog &infoLog,
- gl::Shader *fragmentShader, gl::Shader *vertexShader,
- const std::vector<std::string> &transformFeedbackVaryings,
- GLenum transformFeedbackBufferMode,
- int *registers, std::vector<gl::LinkedVarying> *linkedVaryings,
- std::map<int, gl::VariableLocation> *outputVariables) = 0;
+ virtual LinkResult link(const gl::Data &data, gl::InfoLog &infoLog) = 0;
+ virtual GLboolean validate(const gl::Caps &caps, gl::InfoLog *infoLog) = 0;
virtual void setUniform1fv(GLint location, GLsizei count, const GLfloat *v) = 0;
virtual void setUniform2fv(GLint location, GLsizei count, const GLfloat *v) = 0;
@@ -73,63 +64,20 @@ class ProgramImpl : angle::NonCopyable
virtual void setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) = 0;
virtual void setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) = 0;
- virtual void getUniformfv(GLint location, GLfloat *params) = 0;
- virtual void getUniformiv(GLint location, GLint *params) = 0;
- virtual void getUniformuiv(GLint location, GLuint *params) = 0;
-
- // TODO: The following functions are possibly only applicable to D3D backends. The should be carefully evaluated to
- // determine if they can be removed from this interface.
- virtual GLint getSamplerMapping(gl::SamplerType type, unsigned int samplerIndex, const gl::Caps &caps) const = 0;
- virtual GLenum getSamplerTextureType(gl::SamplerType type, unsigned int samplerIndex) const = 0;
- virtual GLint getUsedSamplerRange(gl::SamplerType type) const = 0;
- virtual void updateSamplerMapping() = 0;
- virtual bool validateSamplers(gl::InfoLog *infoLog, const gl::Caps &caps) = 0;
-
- virtual LinkResult compileProgramExecutables(gl::InfoLog &infoLog, gl::Shader *fragmentShader, gl::Shader *vertexShader,
- int registers) = 0;
-
- virtual bool linkUniforms(gl::InfoLog &infoLog, const gl::Shader &vertexShader, const gl::Shader &fragmentShader,
- const gl::Caps &caps) = 0;
- virtual bool defineUniformBlock(gl::InfoLog &infoLog, const gl::Shader &shader, const sh::InterfaceBlock &interfaceBlock,
- const gl::Caps &caps) = 0;
-
- virtual gl::Error applyUniforms() = 0;
- virtual gl::Error applyUniformBuffers(const gl::Data &data, GLuint uniformBlockBindings[]) = 0;
- virtual bool assignUniformBlockRegister(gl::InfoLog &infoLog, gl::UniformBlock *uniformBlock, GLenum shader,
- unsigned int registerIndex, const gl::Caps &caps) = 0;
-
- const std::vector<gl::LinkedUniform*> &getUniforms() const { return mUniforms; }
- const std::vector<gl::VariableLocation> &getUniformIndices() const { return mUniformIndex; }
- const std::vector<gl::UniformBlock*> &getUniformBlocks() const { return mUniformBlocks; }
- const std::vector<gl::LinkedVarying> &getTransformFeedbackLinkedVaryings() const { return mTransformFeedbackLinkedVaryings; }
- const sh::Attribute *getShaderAttributes() const { return mShaderAttributes; }
- const SemanticIndexArray &getSemanticIndexes() const { return mSemanticIndex; }
-
- std::vector<gl::LinkedUniform*> &getUniforms() { return mUniforms; }
- std::vector<gl::VariableLocation> &getUniformIndices() { return mUniformIndex; }
- std::vector<gl::UniformBlock*> &getUniformBlocks() { return mUniformBlocks; }
- std::vector<gl::LinkedVarying> &getTransformFeedbackLinkedVaryings() { return mTransformFeedbackLinkedVaryings; }
- sh::Attribute *getShaderAttributes() { return mShaderAttributes; }
- SemanticIndexArray &getSemanticIndexes() { return mSemanticIndex; }
-
- gl::LinkedUniform *getUniformByLocation(GLint location) const;
- gl::LinkedUniform *getUniformByName(const std::string &name) const;
- gl::UniformBlock *getUniformBlockByIndex(GLuint blockIndex) const;
-
- GLint getUniformLocation(std::string name);
- GLuint getUniformIndex(std::string name);
- GLuint getUniformBlockIndex(std::string name) const;
-
- virtual void reset();
+ // TODO: synchronize in syncState when dirty bits exist.
+ virtual void setUniformBlockBinding(GLuint uniformBlockIndex, GLuint uniformBlockBinding) = 0;
- protected:
- std::vector<gl::LinkedUniform*> mUniforms;
- std::vector<gl::VariableLocation> mUniformIndex;
- std::vector<gl::UniformBlock*> mUniformBlocks;
- std::vector<gl::LinkedVarying> mTransformFeedbackLinkedVaryings;
+ // May only be called after a successful link operation.
+ // Return false for inactive blocks.
+ virtual bool getUniformBlockSize(const std::string &blockName, size_t *sizeOut) const = 0;
+
+ // May only be called after a successful link operation.
+ // Returns false for inactive members.
+ virtual bool getUniformBlockMemberInfo(const std::string &memberUniformName,
+ sh::BlockMemberInfo *memberInfoOut) const = 0;
- SemanticIndexArray mSemanticIndex;
- sh::Attribute mShaderAttributes[gl::MAX_VERTEX_ATTRIBS];
+ protected:
+ const gl::Program::Data &mData;
};
}
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/ProgramImpl_mock.h b/src/3rdparty/angle/src/libANGLE/renderer/ProgramImpl_mock.h
new file mode 100644
index 0000000000..d6aa238f64
--- /dev/null
+++ b/src/3rdparty/angle/src/libANGLE/renderer/ProgramImpl_mock.h
@@ -0,0 +1,75 @@
+//
+// 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.
+//
+// ProgramImpl_mock.h:
+// Defines a mock of the ProgramImpl class.
+//
+
+#ifndef LIBANGLE_RENDERER_PROGRAMIMPLMOCK_H_
+#define LIBANGLE_RENDERER_PROGRAMIMPLMOCK_H_
+
+#include "gmock/gmock.h"
+
+#include "libANGLE/renderer/ProgramImpl.h"
+
+namespace rx
+{
+
+class MockProgramImpl : public rx::ProgramImpl
+{
+ public:
+ MockProgramImpl() : ProgramImpl(gl::Program::Data()) {}
+ virtual ~MockProgramImpl() { destroy(); }
+
+ MOCK_METHOD2(load, LinkResult(gl::InfoLog &, gl::BinaryInputStream *));
+ MOCK_METHOD1(save, gl::Error(gl::BinaryOutputStream *));
+ MOCK_METHOD1(setBinaryRetrievableHint, void(bool));
+
+ MOCK_METHOD2(link, LinkResult(const gl::Data &, gl::InfoLog &));
+ MOCK_METHOD2(validate, GLboolean(const gl::Caps &, gl::InfoLog *));
+
+ MOCK_METHOD3(setUniform1fv, void(GLint, GLsizei, const GLfloat *));
+ MOCK_METHOD3(setUniform2fv, void(GLint, GLsizei, const GLfloat *));
+ MOCK_METHOD3(setUniform3fv, void(GLint, GLsizei, const GLfloat *));
+ MOCK_METHOD3(setUniform4fv, void(GLint, GLsizei, const GLfloat *));
+ MOCK_METHOD3(setUniform1iv, void(GLint, GLsizei, const GLint *));
+ MOCK_METHOD3(setUniform2iv, void(GLint, GLsizei, const GLint *));
+ MOCK_METHOD3(setUniform3iv, void(GLint, GLsizei, const GLint *));
+ MOCK_METHOD3(setUniform4iv, void(GLint, GLsizei, const GLint *));
+ MOCK_METHOD3(setUniform1uiv, void(GLint, GLsizei, const GLuint *));
+ MOCK_METHOD3(setUniform2uiv, void(GLint, GLsizei, const GLuint *));
+ MOCK_METHOD3(setUniform3uiv, void(GLint, GLsizei, const GLuint *));
+ MOCK_METHOD3(setUniform4uiv, void(GLint, GLsizei, const GLuint *));
+
+ MOCK_METHOD4(setUniformMatrix2fv, void(GLint, GLsizei, GLboolean, const GLfloat *));
+ MOCK_METHOD4(setUniformMatrix3fv, void(GLint, GLsizei, GLboolean, const GLfloat *));
+ MOCK_METHOD4(setUniformMatrix4fv, void(GLint, GLsizei, GLboolean, const GLfloat *));
+ MOCK_METHOD4(setUniformMatrix2x3fv, void(GLint, GLsizei, GLboolean, const GLfloat *));
+ MOCK_METHOD4(setUniformMatrix3x2fv, void(GLint, GLsizei, GLboolean, const GLfloat *));
+ MOCK_METHOD4(setUniformMatrix2x4fv, void(GLint, GLsizei, GLboolean, const GLfloat *));
+ MOCK_METHOD4(setUniformMatrix4x2fv, void(GLint, GLsizei, GLboolean, const GLfloat *));
+ MOCK_METHOD4(setUniformMatrix3x4fv, void(GLint, GLsizei, GLboolean, const GLfloat *));
+ MOCK_METHOD4(setUniformMatrix4x3fv, void(GLint, GLsizei, GLboolean, const GLfloat *));
+
+ MOCK_METHOD2(setUniformBlockBinding, void(GLuint, GLuint));
+ MOCK_CONST_METHOD2(getUniformBlockSize, bool(const std::string &, size_t *));
+ MOCK_CONST_METHOD2(getUniformBlockMemberInfo, bool(const std::string &, sh::BlockMemberInfo *));
+
+ MOCK_METHOD0(destroy, void());
+};
+
+inline ::testing::NiceMock<MockProgramImpl> *MakeProgramMock()
+{
+ ::testing::NiceMock<MockProgramImpl> *programImpl = new ::testing::NiceMock<MockProgramImpl>();
+ // TODO(jmadill): add ON_CALLS for returning methods
+ // We must mock the destructor since NiceMock doesn't work for destructors.
+ EXPECT_CALL(*programImpl, destroy()).Times(1).RetiresOnSaturation();
+
+ return programImpl;
+}
+
+} // namespace rx
+
+#endif // LIBANGLE_RENDERER_PROGRAMIMPLMOCK_H_
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/QueryImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/QueryImpl.h
index bed63ea1b0..d738eb4ffc 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/QueryImpl.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/QueryImpl.h
@@ -26,8 +26,12 @@ class QueryImpl : angle::NonCopyable
virtual gl::Error begin() = 0;
virtual gl::Error end() = 0;
+ virtual gl::Error queryCounter() = 0;
+ virtual gl::Error getResult(GLint *params) = 0;
virtual gl::Error getResult(GLuint *params) = 0;
- virtual gl::Error isResultAvailable(GLuint *available) = 0;
+ virtual gl::Error getResult(GLint64 *params) = 0;
+ virtual gl::Error getResult(GLuint64 *params) = 0;
+ virtual gl::Error isResultAvailable(bool *available) = 0;
GLenum getType() const { return mType; }
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/RenderbufferImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/RenderbufferImpl.h
index 8ce257c833..75b4cdcfee 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/RenderbufferImpl.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/RenderbufferImpl.h
@@ -10,22 +10,27 @@
#define LIBANGLE_RENDERER_RENDERBUFFERIMPL_H_
#include "angle_gl.h"
-
+#include "common/angleutils.h"
#include "libANGLE/Error.h"
+#include "libANGLE/FramebufferAttachment.h"
-#include "common/angleutils.h"
+namespace egl
+{
+class Image;
+}
namespace rx
{
-class RenderbufferImpl : angle::NonCopyable
+class RenderbufferImpl : public FramebufferAttachmentObjectImpl
{
public:
- RenderbufferImpl();
- virtual ~RenderbufferImpl() = 0;
+ RenderbufferImpl() {}
+ virtual ~RenderbufferImpl() {}
virtual gl::Error setStorage(GLenum internalformat, size_t width, size_t height) = 0;
virtual gl::Error setStorageMultisample(size_t samples, GLenum internalformat, size_t width, size_t height) = 0;
+ virtual gl::Error setStorageEGLImageTarget(egl::Image *image) = 0;
};
}
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/RenderbufferImpl_mock.h b/src/3rdparty/angle/src/libANGLE/renderer/RenderbufferImpl_mock.h
new file mode 100644
index 0000000000..c2c67cc76a
--- /dev/null
+++ b/src/3rdparty/angle/src/libANGLE/renderer/RenderbufferImpl_mock.h
@@ -0,0 +1,35 @@
+//
+// 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.
+//
+
+// RenderbufferImpl_mock.h: Defines a mock of the RenderbufferImpl class.
+
+#ifndef LIBANGLE_RENDERER_RENDERBUFFERIMPLMOCK_H_
+#define LIBANGLE_RENDERER_RENDERBUFFERIMPLMOCK_H_
+
+#include "gmock/gmock.h"
+
+#include "libANGLE/Image.h"
+#include "libANGLE/renderer/RenderbufferImpl.h"
+
+namespace rx
+{
+
+class MockRenderbufferImpl : public RenderbufferImpl
+{
+ public:
+ virtual ~MockRenderbufferImpl() { destructor(); }
+ MOCK_METHOD3(setStorage, gl::Error(GLenum, size_t, size_t));
+ MOCK_METHOD4(setStorageMultisample, gl::Error(size_t, GLenum, size_t, size_t));
+ MOCK_METHOD1(setStorageEGLImageTarget, gl::Error(egl::Image *));
+
+ MOCK_METHOD2(getAttachmentRenderTarget, gl::Error(const gl::FramebufferAttachment::Target &, FramebufferAttachmentRenderTarget **));
+
+ MOCK_METHOD0(destructor, void());
+};
+
+}
+
+#endif // LIBANGLE_RENDERER_RENDERBUFFERIMPLMOCK_H_
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/Renderer.cpp b/src/3rdparty/angle/src/libANGLE/renderer/Renderer.cpp
index fbc2ad5d1c..f3f7f55bb9 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/Renderer.cpp
+++ b/src/3rdparty/angle/src/libANGLE/renderer/Renderer.cpp
@@ -14,10 +14,7 @@
namespace rx
{
-
-Renderer::Renderer()
- : mCapsInitialized(false),
- mWorkaroundsInitialized(false)
+Renderer::Renderer() : mCapsInitialized(false)
{
}
@@ -25,48 +22,41 @@ Renderer::~Renderer()
{
}
-const gl::Caps &Renderer::getRendererCaps() const
+void Renderer::ensureCapsInitialized() const
{
if (!mCapsInitialized)
{
- generateCaps(&mCaps, &mTextureCaps, &mExtensions);
+ generateCaps(&mCaps, &mTextureCaps, &mExtensions, &mLimitations);
mCapsInitialized = true;
}
+}
+
+const gl::Caps &Renderer::getRendererCaps() const
+{
+ ensureCapsInitialized();
return mCaps;
}
const gl::TextureCapsMap &Renderer::getRendererTextureCaps() const
{
- if (!mCapsInitialized)
- {
- generateCaps(&mCaps, &mTextureCaps, &mExtensions);
- mCapsInitialized = true;
- }
+ ensureCapsInitialized();
return mTextureCaps;
}
const gl::Extensions &Renderer::getRendererExtensions() const
{
- if (!mCapsInitialized)
- {
- generateCaps(&mCaps, &mTextureCaps, &mExtensions);
- mCapsInitialized = true;
- }
+ ensureCapsInitialized();
return mExtensions;
}
-const Workarounds &Renderer::getWorkarounds() const
+const gl::Limitations &Renderer::getRendererLimitations() const
{
- if (!mWorkaroundsInitialized)
- {
- mWorkarounds = generateWorkarounds();
- mWorkaroundsInitialized = true;
- }
+ ensureCapsInitialized();
- return mWorkarounds;
+ return mLimitations;
}
}
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/Renderer.h b/src/3rdparty/angle/src/libANGLE/renderer/Renderer.h
index b607fe5613..d0da2b140c 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/Renderer.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/Renderer.h
@@ -13,10 +13,10 @@
#include "libANGLE/Caps.h"
#include "libANGLE/Error.h"
#include "libANGLE/Framebuffer.h"
+#include "libANGLE/State.h"
#include "libANGLE/Uniform.h"
#include "libANGLE/angletypes.h"
#include "libANGLE/renderer/ImplFactory.h"
-#include "libANGLE/renderer/Workarounds.h"
#include "common/mathutil.h"
#include <stdint.h>
@@ -30,16 +30,11 @@ class Display;
class Surface;
}
-namespace gl
-{
-class Buffer;
-struct Data;
-}
-
namespace rx
{
struct TranslatedIndexData;
-struct Workarounds;
+struct SourceIndexData;
+struct WorkaroundsD3D;
class DisplayImpl;
class Renderer : public ImplFactory
@@ -51,11 +46,34 @@ class Renderer : public ImplFactory
virtual gl::Error flush() = 0;
virtual gl::Error finish() = 0;
- virtual gl::Error drawArrays(const gl::Data &data, GLenum mode,
- GLint first, GLsizei count, GLsizei instances) = 0;
- virtual gl::Error drawElements(const gl::Data &data, GLenum mode, GLsizei count, GLenum type,
- const GLvoid *indices, GLsizei instances,
- const RangeUI &indexRange) = 0;
+ virtual gl::Error drawArrays(const gl::Data &data, GLenum mode, GLint first, GLsizei count) = 0;
+ virtual gl::Error drawArraysInstanced(const gl::Data &data,
+ GLenum mode,
+ GLint first,
+ GLsizei count,
+ GLsizei instanceCount) = 0;
+
+ virtual gl::Error drawElements(const gl::Data &data,
+ GLenum mode,
+ GLsizei count,
+ GLenum type,
+ const GLvoid *indices,
+ const gl::IndexRange &indexRange) = 0;
+ virtual gl::Error drawElementsInstanced(const gl::Data &data,
+ GLenum mode,
+ GLsizei count,
+ GLenum type,
+ const GLvoid *indices,
+ GLsizei instances,
+ const gl::IndexRange &indexRange) = 0;
+ virtual gl::Error drawRangeElements(const gl::Data &data,
+ GLenum mode,
+ GLuint start,
+ GLuint end,
+ GLsizei count,
+ GLenum type,
+ const GLvoid *indices,
+ const gl::IndexRange &indexRange) = 0;
// lost device
//TODO(jmadill): investigate if this stuff is necessary in GL
@@ -64,27 +82,39 @@ class Renderer : public ImplFactory
virtual bool testDeviceLost() = 0;
virtual bool testDeviceResettable() = 0;
- virtual VendorID getVendorId() const = 0;
virtual std::string getVendorString() const = 0;
virtual std::string getRendererDescription() const = 0;
+ virtual void insertEventMarker(GLsizei length, const char *marker) = 0;
+ virtual void pushGroupMarker(GLsizei length, const char *marker) = 0;
+ virtual void popGroupMarker() = 0;
+
+ virtual void syncState(const gl::State &state, const gl::State::DirtyBits &dirtyBits) = 0;
+
+ // Disjoint timer queries
+ virtual GLint getGPUDisjoint() = 0;
+ virtual GLint64 getTimestamp() = 0;
+
+ // Context switching
+ virtual void onMakeCurrent(const gl::Data &data) = 0;
+
// Renderer capabilities
const gl::Caps &getRendererCaps() const;
const gl::TextureCapsMap &getRendererTextureCaps() const;
const gl::Extensions &getRendererExtensions() const;
- const Workarounds &getWorkarounds() const;
+ const gl::Limitations &getRendererLimitations() const;
private:
- virtual void generateCaps(gl::Caps *outCaps, gl::TextureCapsMap* outTextureCaps, gl::Extensions *outExtensions) const = 0;
- virtual Workarounds generateWorkarounds() const = 0;
+ void ensureCapsInitialized() const;
+ virtual void generateCaps(gl::Caps *outCaps, gl::TextureCapsMap* outTextureCaps,
+ gl::Extensions *outExtensions,
+ gl::Limitations *outLimitations) const = 0;
mutable bool mCapsInitialized;
mutable gl::Caps mCaps;
mutable gl::TextureCapsMap mTextureCaps;
mutable gl::Extensions mExtensions;
-
- mutable bool mWorkaroundsInitialized;
- mutable Workarounds mWorkarounds;
+ mutable gl::Limitations mLimitations;
};
}
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/SamplerImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/SamplerImpl.h
new file mode 100644
index 0000000000..85383cf8e5
--- /dev/null
+++ b/src/3rdparty/angle/src/libANGLE/renderer/SamplerImpl.h
@@ -0,0 +1,25 @@
+//
+// Copyright 2014 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// SamplerImpl.h: Defines the abstract rx::SamplerImpl class.
+
+#ifndef LIBANGLE_RENDERER_SAMPLERIMPL_H_
+#define LIBANGLE_RENDERER_SAMPLERIMPL_H_
+
+#include "common/angleutils.h"
+
+namespace rx
+{
+
+class SamplerImpl : public angle::NonCopyable
+{
+ public:
+ SamplerImpl() {}
+ virtual ~SamplerImpl() {}
+};
+}
+
+#endif // LIBANGLE_RENDERER_SAMPLERIMPL_H_
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/ShaderImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/ShaderImpl.h
index 3011bc57f8..5a466377a5 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/ShaderImpl.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/ShaderImpl.h
@@ -9,8 +9,6 @@
#ifndef LIBANGLE_RENDERER_SHADERIMPL_H_
#define LIBANGLE_RENDERER_SHADERIMPL_H_
-#include <vector>
-
#include "common/angleutils.h"
#include "libANGLE/Shader.h"
@@ -20,36 +18,21 @@ namespace rx
class ShaderImpl : angle::NonCopyable
{
public:
- ShaderImpl() { }
+ ShaderImpl(const gl::Shader::Data &data) : mData(data) {}
virtual ~ShaderImpl() { }
- virtual bool compile(gl::Compiler *compiler, const std::string &source) = 0;
- virtual std::string getDebugInfo() const = 0;
-
- virtual const std::string &getInfoLog() const { return mInfoLog; }
- virtual const std::string &getTranslatedSource() const { return mTranslatedSource; }
+ // Returns additional ShCompile options.
+ virtual int prepareSourceAndReturnOptions(std::stringstream *sourceStream,
+ std::string *sourcePath) = 0;
+ // Returns success for compiling on the driver. Returns success.
+ virtual bool postTranslateCompile(gl::Compiler *compiler, std::string *infoLog) = 0;
- const std::vector<gl::PackedVarying> &getVaryings() const { return mVaryings; }
- const std::vector<sh::Uniform> &getUniforms() const { return mUniforms; }
- const std::vector<sh::InterfaceBlock> &getInterfaceBlocks() const { return mInterfaceBlocks; }
- const std::vector<sh::Attribute> &getActiveAttributes() const { return mActiveAttributes; }
- const std::vector<sh::Attribute> &getActiveOutputVariables() const { return mActiveOutputVariables; }
+ virtual std::string getDebugInfo() const = 0;
- std::vector<gl::PackedVarying> &getVaryings() { return mVaryings; }
- std::vector<sh::Uniform> &getUniforms() { return mUniforms; }
- std::vector<sh::InterfaceBlock> &getInterfaceBlocks() { return mInterfaceBlocks; }
- std::vector<sh::Attribute> &getActiveAttributes() { return mActiveAttributes; }
- std::vector<sh::Attribute> &getActiveOutputVariables() { return mActiveOutputVariables; }
+ const gl::Shader::Data &getData() const { return mData; }
protected:
- std::string mInfoLog;
- std::string mTranslatedSource;
-
- std::vector<gl::PackedVarying> mVaryings;
- std::vector<sh::Uniform> mUniforms;
- std::vector<sh::InterfaceBlock> mInterfaceBlocks;
- std::vector<sh::Attribute> mActiveAttributes;
- std::vector<sh::Attribute> mActiveOutputVariables;
+ const gl::Shader::Data &mData;
};
}
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/SurfaceImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/SurfaceImpl.h
index ca04a42bd1..32125d542c 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/SurfaceImpl.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/SurfaceImpl.h
@@ -11,6 +11,8 @@
#include "common/angleutils.h"
#include "libANGLE/Error.h"
+#include "libANGLE/Framebuffer.h"
+#include "libANGLE/FramebufferAttachment.h"
namespace egl
{
@@ -21,17 +23,20 @@ struct Config;
namespace rx
{
-class SurfaceImpl : angle::NonCopyable
+class FramebufferImpl;
+
+class SurfaceImpl : public FramebufferAttachmentObjectImpl
{
public:
SurfaceImpl();
virtual ~SurfaceImpl();
virtual egl::Error initialize() = 0;
+ virtual FramebufferImpl *createDefaultFramebuffer(const gl::Framebuffer::Data &data) = 0;
virtual egl::Error swap() = 0;
virtual egl::Error postSubBuffer(EGLint x, EGLint y, EGLint width, EGLint height) = 0;
virtual egl::Error querySurfacePointerANGLE(EGLint attribute, void **value) = 0;
- virtual egl::Error bindTexImage(EGLint buffer) = 0;
+ virtual egl::Error bindTexImage(gl::Texture *texture, EGLint buffer) = 0;
virtual egl::Error releaseTexImage(EGLint buffer) = 0;
virtual void setSwapInterval(EGLint interval) = 0;
@@ -40,6 +45,7 @@ class SurfaceImpl : angle::NonCopyable
virtual EGLint getHeight() const = 0;
virtual EGLint isPostSubBufferSupported() const = 0;
+ virtual EGLint getSwapBehavior() const = 0;
};
}
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/TextureImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/TextureImpl.h
index d628906116..ad4ec8d830 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/TextureImpl.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/TextureImpl.h
@@ -9,18 +9,18 @@
#ifndef LIBANGLE_RENDERER_TEXTUREIMPL_H_
#define LIBANGLE_RENDERER_TEXTUREIMPL_H_
-#include "libANGLE/Error.h"
-#include "libANGLE/ImageIndex.h"
-
-#include "common/angleutils.h"
+#include <stdint.h>
#include "angle_gl.h"
-
-#include <stdint.h>
+#include "common/angleutils.h"
+#include "libANGLE/Error.h"
+#include "libANGLE/FramebufferAttachment.h"
+#include "libANGLE/ImageIndex.h"
namespace egl
{
class Surface;
+class Image;
}
namespace gl
@@ -31,16 +31,17 @@ struct Offset;
struct Rectangle;
class Framebuffer;
struct PixelUnpackState;
-struct SamplerState;
+struct TextureState;
}
namespace rx
{
-class TextureImpl : angle::NonCopyable
+class TextureImpl : public FramebufferAttachmentObjectImpl
{
public:
- virtual ~TextureImpl() {};
+ TextureImpl() {}
+ virtual ~TextureImpl() {}
virtual void setUsage(GLenum usage) = 0;
@@ -50,9 +51,9 @@ class TextureImpl : angle::NonCopyable
const gl::PixelUnpackState &unpack, const uint8_t *pixels) = 0;
virtual gl::Error setCompressedImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size,
- const gl::PixelUnpackState &unpack, const uint8_t *pixels) = 0;
+ const gl::PixelUnpackState &unpack, size_t imageSize, const uint8_t *pixels) = 0;
virtual gl::Error setCompressedSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format,
- const gl::PixelUnpackState &unpack, const uint8_t *pixels) = 0;
+ const gl::PixelUnpackState &unpack, size_t imageSize, const uint8_t *pixels) = 0;
virtual gl::Error copyImage(GLenum target, size_t level, const gl::Rectangle &sourceArea, GLenum internalFormat,
const gl::Framebuffer *source) = 0;
@@ -61,7 +62,9 @@ class TextureImpl : angle::NonCopyable
virtual gl::Error setStorage(GLenum target, size_t levels, GLenum internalFormat, const gl::Extents &size) = 0;
- virtual gl::Error generateMipmaps() = 0;
+ virtual gl::Error setEGLImageTarget(GLenum target, egl::Image *image) = 0;
+
+ virtual gl::Error generateMipmaps(const gl::TextureState &textureState) = 0;
virtual void bindTexImage(egl::Surface *surface) = 0;
virtual void releaseTexImage() = 0;
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/TextureImpl_mock.h b/src/3rdparty/angle/src/libANGLE/renderer/TextureImpl_mock.h
new file mode 100644
index 0000000000..3eb43f0033
--- /dev/null
+++ b/src/3rdparty/angle/src/libANGLE/renderer/TextureImpl_mock.h
@@ -0,0 +1,43 @@
+//
+// 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.
+//
+
+// TextureImpl_mock.h: Defines a mock of the TextureImpl class.
+
+#ifndef LIBANGLE_RENDERER_TEXTUREIMPLMOCK_H_
+#define LIBANGLE_RENDERER_TEXTUREIMPLMOCK_H_
+
+#include "gmock/gmock.h"
+
+#include "libANGLE/renderer/TextureImpl.h"
+
+namespace rx
+{
+
+class MockTextureImpl : public TextureImpl
+{
+ public:
+ virtual ~MockTextureImpl() { destructor(); }
+ MOCK_METHOD1(setUsage, void(GLenum));
+ MOCK_METHOD8(setImage, gl::Error(GLenum, size_t, GLenum, const gl::Extents &, GLenum, GLenum, const gl::PixelUnpackState &, const uint8_t *));
+ MOCK_METHOD7(setSubImage, gl::Error(GLenum, size_t, const gl::Box &, GLenum, GLenum, const gl::PixelUnpackState &, const uint8_t *));
+ MOCK_METHOD7(setCompressedImage, gl::Error(GLenum, size_t, GLenum, const gl::Extents &, const gl::PixelUnpackState &, size_t, const uint8_t *));
+ MOCK_METHOD7(setCompressedSubImage, gl::Error(GLenum, size_t, const gl::Box &, GLenum, const gl::PixelUnpackState &, size_t, const uint8_t *));
+ MOCK_METHOD5(copyImage, gl::Error(GLenum, size_t, const gl::Rectangle &, GLenum, const gl::Framebuffer *));
+ MOCK_METHOD5(copySubImage, gl::Error(GLenum, size_t, const gl::Offset &, const gl::Rectangle &, const gl::Framebuffer *));
+ MOCK_METHOD4(setStorage, gl::Error(GLenum, size_t, GLenum, const gl::Extents &));
+ MOCK_METHOD2(setEGLImageTarget, gl::Error(GLenum, egl::Image *));
+ MOCK_METHOD1(generateMipmaps, gl::Error(const gl::TextureState &));
+ MOCK_METHOD1(bindTexImage, void(egl::Surface *));
+ MOCK_METHOD0(releaseTexImage, void(void));
+
+ MOCK_METHOD2(getAttachmentRenderTarget, gl::Error(const gl::FramebufferAttachment::Target &, FramebufferAttachmentRenderTarget **));
+
+ MOCK_METHOD0(destructor, void());
+};
+
+}
+
+#endif // LIBANGLE_RENDERER_TEXTUREIMPLMOCK_H_
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/TransformFeedbackImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/TransformFeedbackImpl.h
index 8f9133cfe5..5df7cad87b 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/TransformFeedbackImpl.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/TransformFeedbackImpl.h
@@ -24,6 +24,9 @@ class TransformFeedbackImpl : angle::NonCopyable
virtual void end() = 0;
virtual void pause() = 0;
virtual void resume() = 0;
+
+ virtual void bindGenericBuffer(const BindingPointer<gl::Buffer> &binding) = 0;
+ virtual void bindIndexedBuffer(size_t index, const OffsetBindingPointer<gl::Buffer> &binding) = 0;
};
}
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/TransformFeedbackImpl_mock.h b/src/3rdparty/angle/src/libANGLE/renderer/TransformFeedbackImpl_mock.h
new file mode 100644
index 0000000000..c7d2fc620d
--- /dev/null
+++ b/src/3rdparty/angle/src/libANGLE/renderer/TransformFeedbackImpl_mock.h
@@ -0,0 +1,37 @@
+//
+// 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.
+//
+
+// TransformFeedbackImpl_mock.h: Defines a mock of the TransformFeedbackImpl class.
+
+#ifndef LIBANGLE_RENDERER_TRANSFORMFEEDBACKIMPLMOCK_H_
+#define LIBANGLE_RENDERER_TRANSFORMFEEDBACKIMPLMOCK_H_
+
+#include "gmock/gmock.h"
+
+#include "libANGLE/renderer/TransformFeedbackImpl.h"
+
+namespace rx
+{
+
+class MockTransformFeedbackImpl : public TransformFeedbackImpl
+{
+ public:
+ ~MockTransformFeedbackImpl() { destructor(); }
+
+ MOCK_METHOD1(begin, void(GLenum primitiveMode));
+ MOCK_METHOD0(end, void());
+ MOCK_METHOD0(pause, void());
+ MOCK_METHOD0(resume, void());
+
+ MOCK_METHOD1(bindGenericBuffer, void(const BindingPointer<gl::Buffer> &));
+ MOCK_METHOD2(bindIndexedBuffer, void(size_t, const OffsetBindingPointer<gl::Buffer> &));
+
+ MOCK_METHOD0(destructor, void());
+};
+
+}
+
+#endif // LIBANGLE_RENDERER_TRANSFORMFEEDBACKIMPLMOCK_H_
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/VertexArrayImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/VertexArrayImpl.h
index 0e25f952c2..13617c7ecb 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/VertexArrayImpl.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/VertexArrayImpl.h
@@ -11,7 +11,7 @@
#include "common/angleutils.h"
#include "libANGLE/Buffer.h"
-#include "libANGLE/VertexAttribute.h"
+#include "libANGLE/VertexArray.h"
namespace rx
{
@@ -19,12 +19,11 @@ namespace rx
class VertexArrayImpl : angle::NonCopyable
{
public:
+ VertexArrayImpl(const gl::VertexArray::Data &data) : mData(data) { }
virtual ~VertexArrayImpl() { }
-
- virtual void setElementArrayBuffer(const gl::Buffer *buffer) = 0;
- virtual void setAttribute(size_t idx, const gl::VertexAttribute &attr) = 0;
- virtual void setAttributeDivisor(size_t idx, GLuint divisor) = 0;
- virtual void enableAttribute(size_t idx, bool enabledState) = 0;
+ virtual void syncState(const gl::VertexArray::DirtyBits &dirtyBits) {}
+ protected:
+ const gl::VertexArray::Data &mData;
};
}
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/BufferD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/BufferD3D.cpp
index 1af8794356..ffca99c3ac 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/BufferD3D.cpp
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/BufferD3D.cpp
@@ -8,6 +8,8 @@
#include "libANGLE/renderer/d3d/BufferD3D.h"
+#include "common/mathutil.h"
+#include "common/utilities.h"
#include "libANGLE/renderer/d3d/IndexBuffer.h"
#include "libANGLE/renderer/d3d/VertexBuffer.h"
@@ -21,7 +23,11 @@ BufferD3D::BufferD3D(BufferFactoryD3D *factory)
mFactory(factory),
mStaticVertexBuffer(nullptr),
mStaticIndexBuffer(nullptr),
- mUnmodifiedDataUse(0)
+ mStaticBufferCache(nullptr),
+ mStaticBufferCacheTotalSize(0),
+ mStaticVertexBufferOutOfDate(false),
+ mUnmodifiedDataUse(0),
+ mUsage(D3D_BUFFER_USAGE_STATIC)
{
updateSerial();
}
@@ -30,6 +36,19 @@ BufferD3D::~BufferD3D()
{
SafeDelete(mStaticVertexBuffer);
SafeDelete(mStaticIndexBuffer);
+
+ emptyStaticBufferCache();
+}
+
+void BufferD3D::emptyStaticBufferCache()
+{
+ if (mStaticBufferCache != nullptr)
+ {
+ SafeDeleteContainer(*mStaticBufferCache);
+ SafeDelete(mStaticBufferCache);
+ }
+
+ mStaticBufferCacheTotalSize = 0;
}
void BufferD3D::updateSerial()
@@ -37,6 +56,30 @@ void BufferD3D::updateSerial()
mSerial = mNextSerial++;
}
+void BufferD3D::updateD3DBufferUsage(GLenum usage)
+{
+ switch (usage)
+ {
+ case GL_STATIC_DRAW:
+ case GL_STATIC_READ:
+ case GL_STATIC_COPY:
+ mUsage = D3D_BUFFER_USAGE_STATIC;
+ initializeStaticData();
+ break;
+
+ case GL_STREAM_DRAW:
+ case GL_STREAM_READ:
+ case GL_STREAM_COPY:
+ case GL_DYNAMIC_READ:
+ case GL_DYNAMIC_COPY:
+ case GL_DYNAMIC_DRAW:
+ mUsage = D3D_BUFFER_USAGE_DYNAMIC;
+ break;
+ default:
+ UNREACHABLE();
+ }
+}
+
void BufferD3D::initializeStaticData()
{
if (!mStaticVertexBuffer)
@@ -49,15 +92,135 @@ void BufferD3D::initializeStaticData()
}
}
-void BufferD3D::invalidateStaticData()
+StaticIndexBufferInterface *BufferD3D::getStaticIndexBuffer()
{
+ return mStaticIndexBuffer;
+}
+
+StaticVertexBufferInterface *BufferD3D::getStaticVertexBuffer(
+ const gl::VertexAttribute &attribute,
+ D3DStaticBufferCreationType creationType)
+{
+ if (!mStaticVertexBuffer)
+ {
+ // Early out if there aren't any static buffers at all
+ ASSERT(mStaticBufferCache == nullptr);
+ return nullptr;
+ }
+
+ if (mStaticBufferCache == nullptr && !mStaticVertexBuffer->isCommitted())
+ {
+ // Early out, the attribute can be added to mStaticVertexBuffer or is already in there
+ return mStaticVertexBuffer;
+ }
+
+ // At this point, see if any of the existing static buffers contains the attribute data
+
+ // If the default static vertex buffer contains the attribute, then return it
+ if (mStaticVertexBuffer->lookupAttribute(attribute, nullptr))
+ {
+ return mStaticVertexBuffer;
+ }
+
+ if (mStaticBufferCache != nullptr)
+ {
+ // If there is a cached static buffer that already contains the attribute, then return it
+ for (StaticVertexBufferInterface *staticBuffer : *mStaticBufferCache)
+ {
+ if (staticBuffer->lookupAttribute(attribute, nullptr))
+ {
+ return staticBuffer;
+ }
+ }
+ }
+
+ if (!mStaticVertexBuffer->isCommitted())
+ {
+ // None of the existing static buffers contain the attribute data and we are able to add
+ // the data to mStaticVertexBuffer, so we should just do so
+ return mStaticVertexBuffer;
+ }
+
+ // At this point, we must create a new static buffer for the attribute data
+ if (creationType != D3D_BUFFER_CREATE_IF_NECESSARY)
+ {
+ return nullptr;
+ }
+
+ ASSERT(mStaticVertexBuffer);
+ ASSERT(mStaticVertexBuffer->isCommitted());
+ unsigned int staticVertexBufferSize = mStaticVertexBuffer->getBufferSize();
+ if (IsUnsignedAdditionSafe(staticVertexBufferSize, mStaticBufferCacheTotalSize))
+ {
+ // Ensure that the total size of the static buffer cache remains less than 4x the
+ // size of the original buffer
+ unsigned int maxStaticCacheSize =
+ IsUnsignedMultiplicationSafe(static_cast<unsigned int>(getSize()), 4u)
+ ? 4u * static_cast<unsigned int>(getSize())
+ : std::numeric_limits<unsigned int>::max();
+
+ // We can't reuse the default static vertex buffer, so we add it to the cache
+ if (staticVertexBufferSize + mStaticBufferCacheTotalSize <= maxStaticCacheSize)
+ {
+ if (mStaticBufferCache == nullptr)
+ {
+ mStaticBufferCache = new std::vector<StaticVertexBufferInterface *>();
+ }
+
+ mStaticBufferCacheTotalSize += staticVertexBufferSize;
+ (*mStaticBufferCache).push_back(mStaticVertexBuffer);
+ mStaticVertexBuffer = nullptr;
+
+ // Then reinitialize the static buffers to create a new static vertex buffer
+ initializeStaticData();
+
+ // Return the default static vertex buffer
+ return mStaticVertexBuffer;
+ }
+ }
+
+ // At this point:
+ // - mStaticVertexBuffer is committed and can't be altered
+ // - mStaticBufferCache is full (or nearly overflowing)
+ // The inputted attribute should be put in some static buffer at some point, but it can't
+ // go in one right now, since mStaticBufferCache is full and we can't delete mStaticVertexBuffer
+ // in case another attribute is relying upon it for the current draw.
+ // We therefore mark mStaticVertexBuffer for deletion at the next possible time.
+ mStaticVertexBufferOutOfDate = true;
+ return nullptr;
+}
+
+void BufferD3D::reinitOutOfDateStaticData()
+{
+ if (mStaticVertexBufferOutOfDate)
+ {
+ // During the last draw the caller tried to use some attribute with static data, but neither
+ // the static buffer cache nor mStaticVertexBuffer contained that data.
+ // Therefore, invalidate mStaticVertexBuffer so that if the caller tries to use that
+ // attribute in the next draw, it'll successfully get put into mStaticVertexBuffer.
+ invalidateStaticData(D3D_BUFFER_INVALIDATE_DEFAULT_BUFFER_ONLY);
+ mStaticVertexBufferOutOfDate = false;
+ }
+}
+
+void BufferD3D::invalidateStaticData(D3DBufferInvalidationType invalidationType)
+{
+ if (invalidationType == D3D_BUFFER_INVALIDATE_WHOLE_CACHE && mStaticBufferCache != nullptr)
+ {
+ emptyStaticBufferCache();
+ }
+
if ((mStaticVertexBuffer && mStaticVertexBuffer->getBufferSize() != 0) || (mStaticIndexBuffer && mStaticIndexBuffer->getBufferSize() != 0))
{
SafeDelete(mStaticVertexBuffer);
SafeDelete(mStaticIndexBuffer);
- // Re-init static data to track that we're in a static buffer
- initializeStaticData();
+ // If the buffer was created with a static usage then we recreate the static
+ // buffers so that they are populated the next time we use this buffer.
+ if (mUsage == D3D_BUFFER_USAGE_STATIC)
+ {
+ initializeStaticData();
+ }
}
mUnmodifiedDataUse = 0;
@@ -68,6 +231,10 @@ void BufferD3D::promoteStaticUsage(int dataSize)
{
if (!mStaticVertexBuffer && !mStaticIndexBuffer)
{
+ // There isn't any scenario that involves promoting static usage and the static buffer cache
+ // being non-empty
+ ASSERT(mStaticBufferCache == nullptr);
+
mUnmodifiedDataUse += dataSize;
if (mUnmodifiedDataUse > 3 * getSize())
@@ -77,4 +244,21 @@ void BufferD3D::promoteStaticUsage(int dataSize)
}
}
-} \ No newline at end of file
+gl::Error BufferD3D::getIndexRange(GLenum type,
+ size_t offset,
+ size_t count,
+ bool primitiveRestartEnabled,
+ gl::IndexRange *outRange)
+{
+ const uint8_t *data = nullptr;
+ gl::Error error = getData(&data);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ *outRange = gl::ComputeIndexRange(type, data + offset, count, primitiveRestartEnabled);
+ return gl::Error(GL_NO_ERROR);
+}
+
+}
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/BufferD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/BufferD3D.h
index a46398f911..a27ca9857a 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/BufferD3D.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/BufferD3D.h
@@ -9,10 +9,11 @@
#ifndef LIBANGLE_RENDERER_D3D_BUFFERD3D_H_
#define LIBANGLE_RENDERER_D3D_BUFFERD3D_H_
-#include "libANGLE/renderer/BufferImpl.h"
#include "libANGLE/angletypes.h"
+#include "libANGLE/renderer/BufferImpl.h"
#include <stdint.h>
+#include <vector>
namespace rx
{
@@ -20,6 +21,24 @@ class BufferFactoryD3D;
class StaticIndexBufferInterface;
class StaticVertexBufferInterface;
+enum D3DBufferUsage
+{
+ D3D_BUFFER_USAGE_STATIC,
+ D3D_BUFFER_USAGE_DYNAMIC,
+};
+
+enum D3DBufferInvalidationType
+{
+ D3D_BUFFER_INVALIDATE_WHOLE_CACHE,
+ D3D_BUFFER_INVALIDATE_DEFAULT_BUFFER_ONLY,
+};
+
+enum D3DStaticBufferCreationType
+{
+ D3D_BUFFER_CREATE_IF_NECESSARY,
+ D3D_BUFFER_DO_NOT_CREATE,
+};
+
class BufferD3D : public BufferImpl
{
public:
@@ -31,16 +50,28 @@ class BufferD3D : public BufferImpl
virtual size_t getSize() const = 0;
virtual bool supportsDirectBinding() const = 0;
virtual void markTransformFeedbackUsage() = 0;
+ virtual gl::Error getData(const uint8_t **outData) = 0;
- StaticVertexBufferInterface *getStaticVertexBuffer() { return mStaticVertexBuffer; }
- StaticIndexBufferInterface *getStaticIndexBuffer() { return mStaticIndexBuffer; }
+ StaticVertexBufferInterface *getStaticVertexBuffer(const gl::VertexAttribute &attribute,
+ D3DStaticBufferCreationType creationType);
+ StaticIndexBufferInterface *getStaticIndexBuffer();
void initializeStaticData();
- void invalidateStaticData();
+ void invalidateStaticData(D3DBufferInvalidationType invalidationType);
+ void reinitOutOfDateStaticData();
+
void promoteStaticUsage(int dataSize);
+ gl::Error getIndexRange(GLenum type,
+ size_t offset,
+ size_t count,
+ bool primitiveRestartEnabled,
+ gl::IndexRange *outRange) override;
+
protected:
void updateSerial();
+ void updateD3DBufferUsage(GLenum usage);
+ void emptyStaticBufferCache();
BufferFactoryD3D *mFactory;
unsigned int mSerial;
@@ -48,7 +79,11 @@ class BufferD3D : public BufferImpl
StaticVertexBufferInterface *mStaticVertexBuffer;
StaticIndexBufferInterface *mStaticIndexBuffer;
+ std::vector<StaticVertexBufferInterface *> *mStaticBufferCache;
+ unsigned int mStaticBufferCacheTotalSize;
+ unsigned int mStaticVertexBufferOutOfDate;
unsigned int mUnmodifiedDataUse;
+ D3DBufferUsage mUsage;
};
}
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/CompilerD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/CompilerD3D.cpp
index a22757cf9f..6f8d1717cd 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/CompilerD3D.cpp
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/CompilerD3D.cpp
@@ -1,128 +1,20 @@
//
-// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved.
+// 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.
//
-
-// CompilerD3D.cpp: Implementation of the rx::CompilerD3D class.
+// CompilerD3D:
+// Implementation of the D3D compiler methods.
+//
#include "libANGLE/renderer/d3d/CompilerD3D.h"
-#include "libANGLE/Caps.h"
-#include "libANGLE/Data.h"
-
-#include "common/debug.h"
-
namespace rx
{
-// Global count of active shader compiler handles. Needed to know when to call ShInitialize and ShFinalize.
-static size_t activeCompilerHandles = 0;
-
-CompilerD3D::CompilerD3D(const gl::Data &data, ShShaderOutput outputType)
- : mSpec(data.clientVersion > 2 ? SH_GLES3_SPEC : SH_GLES2_SPEC),
- mOutputType(outputType),
- mResources(),
- mFragmentCompiler(NULL),
- mVertexCompiler(NULL)
-{
- ASSERT(data.clientVersion == 2 || data.clientVersion == 3);
-
- const gl::Caps &caps = *data.caps;
- const gl::Extensions &extensions = *data.extensions;
-
- ShInitBuiltInResources(&mResources);
- mResources.MaxVertexAttribs = caps.maxVertexAttributes;
- mResources.MaxVertexUniformVectors = caps.maxVertexUniformVectors;
- mResources.MaxVaryingVectors = caps.maxVaryingVectors;
- mResources.MaxVertexTextureImageUnits = caps.maxVertexTextureImageUnits;
- mResources.MaxCombinedTextureImageUnits = caps.maxCombinedTextureImageUnits;
- mResources.MaxTextureImageUnits = caps.maxTextureImageUnits;
- mResources.MaxFragmentUniformVectors = caps.maxFragmentUniformVectors;
- mResources.MaxDrawBuffers = caps.maxDrawBuffers;
- mResources.OES_standard_derivatives = extensions.standardDerivatives;
- mResources.EXT_draw_buffers = extensions.drawBuffers;
- mResources.EXT_shader_texture_lod = 1;
- // resources.OES_EGL_image_external = mRenderer->getShareHandleSupport() ? 1 : 0; // TODO: commented out until the extension is actually supported.
- mResources.FragmentPrecisionHigh = 1; // Shader Model 2+ always supports FP24 (s16e7) which corresponds to highp
- mResources.EXT_frag_depth = 1; // Shader Model 2+ always supports explicit depth output
-
- // GLSL ES 3.0 constants
- mResources.MaxVertexOutputVectors = caps.maxVertexOutputComponents / 4;
- mResources.MaxFragmentInputVectors = caps.maxFragmentInputComponents / 4;
- mResources.MinProgramTexelOffset = caps.minProgramTexelOffset;
- mResources.MaxProgramTexelOffset = caps.maxProgramTexelOffset;
-}
-
-CompilerD3D::~CompilerD3D()
-{
- release();
-}
-
-CompilerD3D *CompilerD3D::makeCompilerD3D(CompilerImpl *compiler)
+CompilerD3D::CompilerD3D(ShShaderOutput translatorOutputType)
+ : mTranslatorOutputType(translatorOutputType)
{
- ASSERT(HAS_DYNAMIC_TYPE(CompilerD3D*, compiler));
- return static_cast<CompilerD3D*>(compiler);
}
-gl::Error CompilerD3D::release()
-{
- if (mFragmentCompiler)
- {
- ShDestruct(mFragmentCompiler);
- mFragmentCompiler = NULL;
-
- ASSERT(activeCompilerHandles > 0);
- activeCompilerHandles--;
- }
-
- if (mVertexCompiler)
- {
- ShDestruct(mVertexCompiler);
- mVertexCompiler = NULL;
-
- ASSERT(activeCompilerHandles > 0);
- activeCompilerHandles--;
- }
-
- if (activeCompilerHandles == 0)
- {
- ShFinalize();
- }
-
- return gl::Error(GL_NO_ERROR);
-}
-
-ShHandle CompilerD3D::getCompilerHandle(GLenum type)
-{
- ShHandle *compiler = NULL;
- switch (type)
- {
- case GL_VERTEX_SHADER:
- compiler = &mVertexCompiler;
- break;
-
- case GL_FRAGMENT_SHADER:
- compiler = &mFragmentCompiler;
- break;
-
- default:
- UNREACHABLE();
- return NULL;
- }
-
- if (!(*compiler))
- {
- if (activeCompilerHandles == 0)
- {
- ShInitialize();
- }
-
- *compiler = ShConstructCompiler(type, mSpec, mOutputType, &mResources);
- activeCompilerHandles++;
- }
-
- return *compiler;
-}
-
-}
+} // namespace rx
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/CompilerD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/CompilerD3D.h
index 0f83e4f8c8..8f4334963d 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/CompilerD3D.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/CompilerD3D.h
@@ -10,14 +10,7 @@
#define LIBANGLE_RENDERER_COMPILERD3D_H_
#include "libANGLE/renderer/CompilerImpl.h"
-#include "libANGLE/Caps.h"
-
-#include "GLSLANG/ShaderLang.h"
-
-namespace gl
-{
-struct Data;
-}
+#include "libANGLE/renderer/d3d/RendererD3D.h"
namespace rx
{
@@ -25,22 +18,14 @@ namespace rx
class CompilerD3D : public CompilerImpl
{
public:
- CompilerD3D(const gl::Data &data, ShShaderOutput outputType);
- virtual ~CompilerD3D();
+ CompilerD3D(ShShaderOutput translatorOutputType);
+ ~CompilerD3D() override {}
- static CompilerD3D *makeCompilerD3D(CompilerImpl *compiler);
-
- gl::Error release() override;
-
- ShHandle getCompilerHandle(GLenum type);
+ gl::Error release() override { return gl::Error(GL_NO_ERROR); }
+ ShShaderOutput getTranslatorOutputType() const override { return mTranslatorOutputType; }
private:
- ShShaderSpec mSpec;
- ShShaderOutput mOutputType;
- ShBuiltInResources mResources;
-
- ShHandle mFragmentCompiler;
- ShHandle mVertexCompiler;
+ ShShaderOutput mTranslatorOutputType;
};
}
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/DeviceD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/DeviceD3D.cpp
new file mode 100644
index 0000000000..f40e6e6cab
--- /dev/null
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/DeviceD3D.cpp
@@ -0,0 +1,102 @@
+//
+// 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.
+//
+
+// DeviceD3D.cpp: D3D implementation of egl::Device
+
+#include "libANGLE/renderer/d3d/DeviceD3D.h"
+#include "libANGLE/renderer/d3d/RendererD3D.h"
+
+#include "libANGLE/Device.h"
+#include "libANGLE/Display.h"
+
+#include <EGL/eglext.h>
+
+namespace rx
+{
+
+DeviceD3D::DeviceD3D()
+ : mDevice(0), mDeviceType(0), mDeviceExternallySourced(false), mIsInitialized(false)
+{
+}
+
+DeviceD3D::~DeviceD3D()
+{
+#if defined(ANGLE_ENABLE_D3D11)
+ if (mDeviceType == EGL_D3D11_DEVICE_ANGLE)
+ {
+ // DeviceD3D holds a ref to an externally-sourced D3D11 device. We must release it.
+ ID3D11Device *device = reinterpret_cast<ID3D11Device *>(mDevice);
+ device->Release();
+ }
+#endif
+}
+
+egl::Error DeviceD3D::getDevice(void **outValue)
+{
+ if (!mIsInitialized)
+ {
+ *outValue = nullptr;
+ return egl::Error(EGL_BAD_DEVICE_EXT);
+ }
+
+ *outValue = mDevice;
+ return egl::Error(EGL_SUCCESS);
+}
+
+egl::Error DeviceD3D::initialize(void *device,
+ EGLint deviceType,
+ EGLBoolean deviceExternallySourced)
+{
+ ASSERT(!mIsInitialized);
+ if (mIsInitialized)
+ {
+ return egl::Error(EGL_BAD_DEVICE_EXT);
+ }
+
+ mDevice = device;
+ mDeviceType = deviceType;
+ mDeviceExternallySourced = !!deviceExternallySourced;
+
+#if defined(ANGLE_ENABLE_D3D11)
+ if (mDeviceType == EGL_D3D11_DEVICE_ANGLE)
+ {
+ // Validate the device
+ IUnknown *iunknown = reinterpret_cast<IUnknown *>(device);
+
+ ID3D11Device *d3dDevice = nullptr;
+ HRESULT hr =
+ iunknown->QueryInterface(__uuidof(ID3D11Device), reinterpret_cast<void **>(&d3dDevice));
+ if (FAILED(hr))
+ {
+ return egl::Error(EGL_BAD_ATTRIBUTE, "Invalid D3D device passed into EGLDeviceEXT");
+ }
+
+ // The QI to ID3D11Device adds a ref to the D3D11 device.
+ // Deliberately don't release the ref here, so that the DeviceD3D holds a ref to the
+ // D3D11 device.
+ }
+ else
+#endif
+ {
+ ASSERT(!mDeviceExternallySourced);
+ }
+
+ mIsInitialized = true;
+
+ return egl::Error(EGL_SUCCESS);
+}
+
+EGLint DeviceD3D::getType()
+{
+ return mDeviceType;
+}
+
+void DeviceD3D::generateExtensions(egl::DeviceExtensions *outExtensions) const
+{
+ outExtensions->deviceD3D = true;
+}
+
+}
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/DeviceD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/DeviceD3D.h
new file mode 100644
index 0000000000..1dd9979708
--- /dev/null
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/DeviceD3D.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.
+//
+
+// DeviceD3D.h: D3D implementation of egl::Device
+
+#ifndef LIBANGLE_RENDERER_D3D_DEVICED3D_H_
+#define LIBANGLE_RENDERER_D3D_DEVICED3D_H_
+
+#include "libANGLE/Device.h"
+#include "libANGLE/renderer/DeviceImpl.h"
+#include "libANGLE/renderer/d3d/RendererD3D.h"
+
+namespace rx
+{
+class DeviceD3D : public DeviceImpl
+{
+ public:
+ DeviceD3D();
+ ~DeviceD3D() override;
+
+ egl::Error initialize(void *device, EGLint deviceType, EGLBoolean external);
+ egl::Error getDevice(void **outValue) override;
+ EGLint getType() override;
+ void generateExtensions(egl::DeviceExtensions *outExtensions) const override;
+ bool deviceExternallySourced() override { return mDeviceExternallySourced; }
+
+ private:
+ void *mDevice;
+ EGLint mDeviceType;
+ bool mDeviceExternallySourced;
+ bool mIsInitialized;
+};
+
+}
+
+#endif // LIBANGLE_RENDERER_D3D_DEVICED3D_H_
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/DisplayD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/DisplayD3D.cpp
index add5d62fae..d4dc702582 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/DisplayD3D.cpp
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/DisplayD3D.cpp
@@ -12,10 +12,12 @@
#include "libANGLE/Config.h"
#include "libANGLE/Display.h"
#include "libANGLE/Surface.h"
+#include "libANGLE/histogram_macros.h"
+#include "libANGLE/renderer/d3d/EGLImageD3D.h"
#include "libANGLE/renderer/d3d/RendererD3D.h"
#include "libANGLE/renderer/d3d/SurfaceD3D.h"
#include "libANGLE/renderer/d3d/SwapChainD3D.h"
-#include "platform/Platform.h"
+#include "libANGLE/renderer/d3d/DeviceD3D.h"
#include <EGL/eglext.h>
@@ -33,7 +35,7 @@
#if !defined(ANGLE_DEFAULT_D3D11)
// Enables use of the Direct3D 11 API for a default display, when available
-# define ANGLE_DEFAULT_D3D11 0
+# define ANGLE_DEFAULT_D3D11 1
#endif
namespace rx
@@ -53,10 +55,13 @@ egl::Error CreateRendererD3D(egl::Display *display, RendererD3D **outRenderer)
std::vector<CreateRendererD3DFunction> rendererCreationFunctions;
- const auto &attribMap = display->getAttributeMap();
- EGLNativeDisplayType nativeDisplay = display->getNativeDisplayId();
+ if (display->getPlatform() == EGL_PLATFORM_ANGLE_ANGLE)
+ {
+ const auto &attribMap = display->getAttributeMap();
+ EGLNativeDisplayType nativeDisplay = display->getNativeDisplayId();
- EGLint requestedDisplayType = attribMap.get(EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE);
+ EGLint requestedDisplayType =
+ attribMap.get(EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE);
# if defined(ANGLE_ENABLE_D3D11)
if (nativeDisplay == EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE ||
@@ -75,27 +80,41 @@ egl::Error CreateRendererD3D(egl::Display *display, RendererD3D **outRenderer)
}
# endif
- if (nativeDisplay != EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE &&
- nativeDisplay != EGL_D3D11_ONLY_DISPLAY_ANGLE &&
- requestedDisplayType == EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE)
- {
+ if (nativeDisplay != EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE &&
+ nativeDisplay != EGL_D3D11_ONLY_DISPLAY_ANGLE &&
+ requestedDisplayType == EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE)
+ {
// The default display is requested, try the D3D9 and D3D11 renderers, order them using
// the definition of ANGLE_DEFAULT_D3D11
# if ANGLE_DEFAULT_D3D11
# if defined(ANGLE_ENABLE_D3D11)
- rendererCreationFunctions.push_back(CreateTypedRendererD3D<Renderer11>);
+ rendererCreationFunctions.push_back(CreateTypedRendererD3D<Renderer11>);
# endif
# if defined(ANGLE_ENABLE_D3D9)
- rendererCreationFunctions.push_back(CreateTypedRendererD3D<Renderer9>);
+ rendererCreationFunctions.push_back(CreateTypedRendererD3D<Renderer9>);
# endif
# else
# if defined(ANGLE_ENABLE_D3D9)
- rendererCreationFunctions.push_back(CreateTypedRendererD3D<Renderer9>);
+ rendererCreationFunctions.push_back(CreateTypedRendererD3D<Renderer9>);
# endif
# if defined(ANGLE_ENABLE_D3D11)
- rendererCreationFunctions.push_back(CreateTypedRendererD3D<Renderer11>);
+ rendererCreationFunctions.push_back(CreateTypedRendererD3D<Renderer11>);
# endif
# endif
+ }
+ }
+ else if (display->getPlatform() == EGL_PLATFORM_DEVICE_EXT)
+ {
+#if defined(ANGLE_ENABLE_D3D11)
+ if (display->getDevice()->getType() == EGL_D3D11_DEVICE_ANGLE)
+ {
+ rendererCreationFunctions.push_back(CreateTypedRendererD3D<Renderer11>);
+ }
+#endif
+ }
+ else
+ {
+ UNIMPLEMENTED();
}
egl::Error result(EGL_NOT_INITIALIZED, "No available renderers.");
@@ -108,10 +127,9 @@ egl::Error CreateRendererD3D(egl::Display *display, RendererD3D **outRenderer)
if (renderer->getRendererClass() == RENDERER_D3D11)
{
ASSERT(result.getID() >= 0 && result.getID() < NUM_D3D11_INIT_ERRORS);
-
- angle::Platform *platform = ANGLEPlatformCurrent();
- platform->histogramEnumeration("GPU.ANGLE.D3D11InitializeResult",
- result.getID(), NUM_D3D11_INIT_ERRORS);
+ ANGLE_HISTOGRAM_ENUMERATION("GPU.ANGLE.D3D11InitializeResult",
+ result.getID(),
+ NUM_D3D11_INIT_ERRORS);
}
# endif
@@ -119,10 +137,9 @@ egl::Error CreateRendererD3D(egl::Display *display, RendererD3D **outRenderer)
if (renderer->getRendererClass() == RENDERER_D3D9)
{
ASSERT(result.getID() >= 0 && result.getID() < NUM_D3D9_INIT_ERRORS);
-
- angle::Platform *platform = ANGLEPlatformCurrent();
- platform->histogramEnumeration("GPU.ANGLE.D3D9InitializeResult",
- result.getID(), NUM_D3D9_INIT_ERRORS);
+ ANGLE_HISTOGRAM_ENUMERATION("GPU.ANGLE.D3D9InitializeResult",
+ result.getID(),
+ NUM_D3D9_INIT_ERRORS);
}
# endif
@@ -141,19 +158,22 @@ egl::Error CreateRendererD3D(egl::Display *display, RendererD3D **outRenderer)
return result;
}
-DisplayD3D::DisplayD3D()
- : mRenderer(nullptr)
+DisplayD3D::DisplayD3D() : mRenderer(nullptr)
{
}
-egl::Error DisplayD3D::createWindowSurface(const egl::Config *configuration, EGLNativeWindowType window,
- const egl::AttributeMap &attribs, SurfaceImpl **outSurface)
+
+SurfaceImpl *DisplayD3D::createWindowSurface(const egl::Config *configuration,
+ EGLNativeWindowType window,
+ const egl::AttributeMap &attribs)
{
ASSERT(mRenderer != nullptr);
EGLint width = attribs.get(EGL_WIDTH, 0);
EGLint height = attribs.get(EGL_HEIGHT, 0);
EGLint fixedSize = attribs.get(EGL_FIXED_SIZE_ANGLE, EGL_FALSE);
+ EGLint orientation = attribs.get(EGL_SURFACE_ORIENTATION_ANGLE, 0);
+ EGLint directComposition = attribs.get(EGL_DIRECT_COMPOSITION_ANGLE, EGL_FALSE);
if (!fixedSize)
{
@@ -161,81 +181,60 @@ egl::Error DisplayD3D::createWindowSurface(const egl::Config *configuration, EGL
height = -1;
}
- SurfaceD3D *surface = SurfaceD3D::createFromWindow(mRenderer, mDisplay, configuration, window, fixedSize,
- width, height);
- egl::Error error = surface->initialize();
- if (error.isError())
- {
- SafeDelete(surface);
- return error;
- }
-
- *outSurface = surface;
- return egl::Error(EGL_SUCCESS);
+ return SurfaceD3D::createFromWindow(mRenderer, mDisplay, configuration, window, fixedSize,
+ directComposition, width, height, orientation);
}
-egl::Error DisplayD3D::createPbufferSurface(const egl::Config *configuration, const egl::AttributeMap &attribs,
- SurfaceImpl **outSurface)
+SurfaceImpl *DisplayD3D::createPbufferSurface(const egl::Config *configuration,
+ const egl::AttributeMap &attribs)
{
ASSERT(mRenderer != nullptr);
EGLint width = attribs.get(EGL_WIDTH, 0);
EGLint height = attribs.get(EGL_HEIGHT, 0);
- SurfaceD3D *surface = SurfaceD3D::createOffscreen(mRenderer, mDisplay, configuration, NULL, width, height);
- egl::Error error = surface->initialize();
- if (error.isError())
- {
- SafeDelete(surface);
- return error;
- }
-
- *outSurface = surface;
- return egl::Error(EGL_SUCCESS);
+ return SurfaceD3D::createOffscreen(mRenderer, mDisplay, configuration, nullptr, width, height);
}
-egl::Error DisplayD3D::createPbufferFromClientBuffer(const egl::Config *configuration, EGLClientBuffer shareHandle,
- const egl::AttributeMap &attribs, SurfaceImpl **outSurface)
+SurfaceImpl *DisplayD3D::createPbufferFromClientBuffer(const egl::Config *configuration,
+ EGLClientBuffer shareHandle,
+ const egl::AttributeMap &attribs)
{
ASSERT(mRenderer != nullptr);
EGLint width = attribs.get(EGL_WIDTH, 0);
EGLint height = attribs.get(EGL_HEIGHT, 0);
- SurfaceD3D *surface = SurfaceD3D::createOffscreen(mRenderer, mDisplay, configuration, shareHandle,
- width, height);
- egl::Error error = surface->initialize();
- if (error.isError())
- {
- SafeDelete(surface);
- return error;
- }
-
- *outSurface = surface;
- return egl::Error(EGL_SUCCESS);
+ return SurfaceD3D::createOffscreen(
+ mRenderer, mDisplay, configuration, shareHandle, width, height);
}
-egl::Error DisplayD3D::createPixmapSurface(const egl::Config *configuration, NativePixmapType nativePixmap,
- const egl::AttributeMap &attribs, SurfaceImpl **outSurface)
+SurfaceImpl *DisplayD3D::createPixmapSurface(const egl::Config *configuration,
+ NativePixmapType nativePixmap,
+ const egl::AttributeMap &attribs)
{
- ASSERT(mRenderer != nullptr);
-
UNIMPLEMENTED();
- *outSurface = nullptr;
- return egl::Error(EGL_BAD_DISPLAY);
+ return nullptr;
}
-egl::Error DisplayD3D::createContext(const egl::Config *config, const gl::Context *shareContext, const egl::AttributeMap &attribs,
- gl::Context **outContext)
+ImageImpl *DisplayD3D::createImage(EGLenum target,
+ egl::ImageSibling *buffer,
+ const egl::AttributeMap &attribs)
{
- ASSERT(mRenderer != nullptr);
+ return new EGLImageD3D(mRenderer, target, buffer, attribs);
+}
- EGLint clientVersion = attribs.get(EGL_CONTEXT_CLIENT_VERSION, 1);
- bool notifyResets = (attribs.get(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT, EGL_NO_RESET_NOTIFICATION_EXT) == EGL_LOSE_CONTEXT_ON_RESET_EXT);
- bool robustAccess = (attribs.get(EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT, EGL_FALSE) == EGL_TRUE);
+egl::Error DisplayD3D::getDevice(DeviceImpl **device)
+{
+ return mRenderer->getEGLDevice(device);
+}
- *outContext = new gl::Context(config, clientVersion, shareContext, mRenderer, notifyResets, robustAccess);
- return egl::Error(EGL_SUCCESS);
+gl::Context *DisplayD3D::createContext(const egl::Config *config,
+ const gl::Context *shareContext,
+ const egl::AttributeMap &attribs)
+{
+ ASSERT(mRenderer != nullptr);
+ return new gl::Context(config, shareContext, mRenderer, attribs);
}
egl::Error DisplayD3D::makeCurrent(egl::Surface *drawSurface, egl::Surface *readSurface, gl::Context *context)
@@ -247,7 +246,13 @@ egl::Error DisplayD3D::initialize(egl::Display *display)
{
ASSERT(mRenderer == nullptr && display != nullptr);
mDisplay = display;
- return CreateRendererD3D(display, &mRenderer);
+ egl::Error error = CreateRendererD3D(display, &mRenderer);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ return egl::Error(EGL_SUCCESS);
}
void DisplayD3D::terminate()
@@ -276,9 +281,8 @@ bool DisplayD3D::testDeviceLost()
egl::Error DisplayD3D::restoreLostDevice()
{
// Release surface resources to make the Reset() succeed
- for (auto it = mSurfaceSet.cbegin(); it != mSurfaceSet.cend(); ++it)
+ for (auto &surface : mSurfaceSet)
{
- const auto &surface = *it;
if (surface->getBoundTexture())
{
surface->releaseTexImage(EGL_BACK_BUFFER);
@@ -293,9 +297,8 @@ egl::Error DisplayD3D::restoreLostDevice()
}
// Restore any surfaces that may have been lost
- for (auto it = mSurfaceSet.cbegin(); it != mSurfaceSet.cend(); ++it)
+ for (const auto &surface : mSurfaceSet)
{
- const auto &surface = *it;
SurfaceD3D *surfaceD3D = GetImplAs<SurfaceD3D>(surface);
egl::Error error = surfaceD3D->resetSwapChain();
@@ -315,24 +318,7 @@ bool DisplayD3D::isValidNativeWindow(EGLNativeWindowType window) const
void DisplayD3D::generateExtensions(egl::DisplayExtensions *outExtensions) const
{
- outExtensions->createContextRobustness = true;
-
- // ANGLE-specific extensions
- if (mRenderer->getShareHandleSupport())
- {
- outExtensions->d3dShareHandleClientBuffer = true;
- outExtensions->surfaceD3DTexture2DShareHandle = true;
- }
-
- outExtensions->querySurfacePointer = true;
- outExtensions->windowFixedSize = true;
-
- if (mRenderer->getPostSubBufferSupport())
- {
- outExtensions->postSubBuffer = true;
- }
-
- outExtensions->createContext = true;
+ mRenderer->generateDisplayExtensions(outExtensions);
}
std::string DisplayD3D::getVendorString() const
@@ -354,4 +340,17 @@ void DisplayD3D::generateCaps(egl::Caps *outCaps) const
outCaps->textureNPOT = mRenderer->getRendererExtensions().textureNPOT;
}
+egl::Error DisplayD3D::waitClient() const
+{
+ // Unimplemented as it is a noop on D3D
+ return egl::Error(EGL_SUCCESS);
+}
+
+egl::Error DisplayD3D::waitNative(EGLint engine,
+ egl::Surface *drawSurface,
+ egl::Surface *readSurface) const
+{
+ // Unimplemented as it is a noop on D3D
+ return egl::Error(EGL_SUCCESS);
+}
}
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/DisplayD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/DisplayD3D.h
index f007ba9a19..0ce196dea2 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/DisplayD3D.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/DisplayD3D.h
@@ -10,6 +10,7 @@
#define LIBANGLE_RENDERER_D3D_DISPLAYD3D_H_
#include "libANGLE/renderer/DisplayImpl.h"
+#include "libANGLE/Device.h"
namespace rx
{
@@ -23,17 +24,26 @@ class DisplayD3D : public DisplayImpl
egl::Error initialize(egl::Display *display) override;
virtual void terminate() override;
- egl::Error createWindowSurface(const egl::Config *configuration, EGLNativeWindowType window, const egl::AttributeMap &attribs,
- SurfaceImpl **outSurface) override;
- egl::Error createPbufferSurface(const egl::Config *configuration, const egl::AttributeMap &attribs,
- SurfaceImpl **outSurface) override;
- egl::Error createPbufferFromClientBuffer(const egl::Config *configuration, EGLClientBuffer shareHandle,
- const egl::AttributeMap &attribs, SurfaceImpl **outSurface) override;
- egl::Error createPixmapSurface(const egl::Config *configuration, NativePixmapType nativePixmap,
- const egl::AttributeMap &attribs, SurfaceImpl **outSurface) override;
-
- egl::Error createContext(const egl::Config *config, const gl::Context *shareContext, const egl::AttributeMap &attribs,
- gl::Context **outContext) override;
+ // Surface creation
+ SurfaceImpl *createWindowSurface(const egl::Config *configuration,
+ EGLNativeWindowType window,
+ const egl::AttributeMap &attribs) override;
+ SurfaceImpl *createPbufferSurface(const egl::Config *configuration,
+ const egl::AttributeMap &attribs) override;
+ SurfaceImpl *createPbufferFromClientBuffer(const egl::Config *configuration,
+ EGLClientBuffer shareHandle,
+ const egl::AttributeMap &attribs) override;
+ SurfaceImpl *createPixmapSurface(const egl::Config *configuration,
+ NativePixmapType nativePixmap,
+ const egl::AttributeMap &attribs) override;
+
+ ImageImpl *createImage(EGLenum target,
+ egl::ImageSibling *buffer,
+ const egl::AttributeMap &attribs) override;
+
+ gl::Context *createContext(const egl::Config *config,
+ const gl::Context *shareContext,
+ const egl::AttributeMap &attribs) override;
egl::Error makeCurrent(egl::Surface *drawSurface, egl::Surface *readSurface, gl::Context *context) override;
@@ -45,8 +55,15 @@ class DisplayD3D : public DisplayImpl
bool isValidNativeWindow(EGLNativeWindowType window) const override;
+ egl::Error getDevice(DeviceImpl **device) override;
+
std::string getVendorString() const override;
+ egl::Error waitClient() const override;
+ egl::Error waitNative(EGLint engine,
+ egl::Surface *drawSurface,
+ egl::Surface *readSurface) const override;
+
private:
void generateExtensions(egl::DisplayExtensions *outExtensions) const override;
void generateCaps(egl::Caps *outCaps) const override;
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/DynamicHLSL.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/DynamicHLSL.cpp
index 0dbc30ae36..42a534f573 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/DynamicHLSL.cpp
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/DynamicHLSL.cpp
@@ -10,14 +10,13 @@
#include "common/utilities.h"
#include "compiler/translator/blocklayoutHLSL.h"
-#include "libANGLE/renderer/d3d/ShaderD3D.h"
-#include "libANGLE/renderer/d3d/RendererD3D.h"
#include "libANGLE/Program.h"
#include "libANGLE/Shader.h"
#include "libANGLE/formatutils.h"
-
-// For use with ArrayString, see angleutils.h
-static_assert(GL_INVALID_INDEX == UINT_MAX, "GL_INVALID_INDEX must be equal to the max unsigned int.");
+#include "libANGLE/renderer/d3d/ProgramD3D.h"
+#include "libANGLE/renderer/d3d/RendererD3D.h"
+#include "libANGLE/renderer/d3d/ShaderD3D.h"
+#include "libANGLE/renderer/d3d/VaryingPacking.h"
using namespace gl;
@@ -31,12 +30,17 @@ std::string HLSLComponentTypeString(GLenum componentType)
{
switch (componentType)
{
- case GL_UNSIGNED_INT: return "uint";
- case GL_INT: return "int";
- case GL_UNSIGNED_NORMALIZED:
- case GL_SIGNED_NORMALIZED:
- case GL_FLOAT: return "float";
- default: UNREACHABLE(); return "not-component-type";
+ case GL_UNSIGNED_INT:
+ return "uint";
+ case GL_INT:
+ return "int";
+ case GL_UNSIGNED_NORMALIZED:
+ case GL_SIGNED_NORMALIZED:
+ case GL_FLOAT:
+ return "float";
+ default:
+ UNREACHABLE();
+ return "not-component-type";
}
}
@@ -49,16 +53,27 @@ std::string HLSLMatrixTypeString(GLenum type)
{
switch (type)
{
- case GL_FLOAT_MAT2: return "float2x2";
- case GL_FLOAT_MAT3: return "float3x3";
- case GL_FLOAT_MAT4: return "float4x4";
- case GL_FLOAT_MAT2x3: return "float2x3";
- case GL_FLOAT_MAT3x2: return "float3x2";
- case GL_FLOAT_MAT2x4: return "float2x4";
- case GL_FLOAT_MAT4x2: return "float4x2";
- case GL_FLOAT_MAT3x4: return "float3x4";
- case GL_FLOAT_MAT4x3: return "float4x3";
- default: UNREACHABLE(); return "not-matrix-type";
+ case GL_FLOAT_MAT2:
+ return "float2x2";
+ case GL_FLOAT_MAT3:
+ return "float3x3";
+ case GL_FLOAT_MAT4:
+ return "float4x4";
+ case GL_FLOAT_MAT2x3:
+ return "float2x3";
+ case GL_FLOAT_MAT3x2:
+ return "float3x2";
+ case GL_FLOAT_MAT2x4:
+ return "float2x4";
+ case GL_FLOAT_MAT4x2:
+ return "float4x2";
+ case GL_FLOAT_MAT3x4:
+ return "float3x4";
+ case GL_FLOAT_MAT4x3:
+ return "float4x3";
+ default:
+ UNREACHABLE();
+ return "not-matrix-type";
}
}
@@ -69,11 +84,13 @@ std::string HLSLTypeString(GLenum type)
return HLSLMatrixTypeString(type);
}
- return HLSLComponentTypeString(gl::VariableComponentType(type), gl::VariableComponentCount(type));
+ return HLSLComponentTypeString(gl::VariableComponentType(type),
+ gl::VariableComponentCount(type));
}
-const PixelShaderOutputVariable *FindOutputAtLocation(const std::vector<PixelShaderOutputVariable> &outputVariables,
- unsigned int location)
+const PixelShaderOutputVariable *FindOutputAtLocation(
+ const std::vector<PixelShaderOutputVariable> &outputVariables,
+ unsigned int location)
{
for (size_t variableIndex = 0; variableIndex < outputVariables.size(); ++variableIndex)
{
@@ -83,314 +100,102 @@ const PixelShaderOutputVariable *FindOutputAtLocation(const std::vector<PixelSha
}
}
- return NULL;
-}
-
-const std::string VERTEX_ATTRIBUTE_STUB_STRING = "@@ VERTEX ATTRIBUTES @@";
-const std::string PIXEL_OUTPUT_STUB_STRING = "@@ PIXEL OUTPUT @@";
-
-}
-
-DynamicHLSL::DynamicHLSL(RendererD3D *const renderer)
- : mRenderer(renderer)
-{
+ return nullptr;
}
-static bool packVarying(PackedVarying *varying, const int maxVaryingVectors, VaryingPacking packing)
+void WriteArrayString(std::stringstream &strstr, unsigned int i)
{
- // Make sure we use transposed matrix types to count registers correctly.
- int registers = 0;
- int elements = 0;
-
- if (varying->isStruct())
- {
- registers = HLSLVariableRegisterCount(*varying, true) * varying->elementCount();
- elements = 4;
- }
- else
+ static_assert(GL_INVALID_INDEX == UINT_MAX,
+ "GL_INVALID_INDEX must be equal to the max unsigned int.");
+ if (i == UINT_MAX)
{
- GLenum transposedType = TransposeMatrixType(varying->type);
- registers = VariableRowCount(transposedType) * varying->elementCount();
- elements = VariableColumnCount(transposedType);
+ return;
}
- if (elements >= 2 && elements <= 4)
- {
- for (int r = 0; r <= maxVaryingVectors - registers; r++)
- {
- bool available = true;
-
- for (int y = 0; y < registers && available; y++)
- {
- for (int x = 0; x < elements && available; x++)
- {
- if (packing[r + y][x])
- {
- available = false;
- }
- }
- }
-
- if (available)
- {
- varying->registerIndex = r;
- varying->columnIndex = 0;
-
- for (int y = 0; y < registers; y++)
- {
- for (int x = 0; x < elements; x++)
- {
- packing[r + y][x] = &*varying;
- }
- }
-
- return true;
- }
- }
-
- if (elements == 2)
- {
- for (int r = maxVaryingVectors - registers; r >= 0; r--)
- {
- bool available = true;
-
- for (int y = 0; y < registers && available; y++)
- {
- for (int x = 2; x < 4 && available; x++)
- {
- if (packing[r + y][x])
- {
- available = false;
- }
- }
- }
-
- if (available)
- {
- varying->registerIndex = r;
- varying->columnIndex = 2;
-
- for (int y = 0; y < registers; y++)
- {
- for (int x = 2; x < 4; x++)
- {
- packing[r + y][x] = &*varying;
- }
- }
-
- return true;
- }
- }
- }
- }
- else if (elements == 1)
- {
- int space[4] = { 0 };
-
- for (int y = 0; y < maxVaryingVectors; y++)
- {
- for (int x = 0; x < 4; x++)
- {
- space[x] += packing[y][x] ? 0 : 1;
- }
- }
-
- int column = 0;
-
- for (int x = 0; x < 4; x++)
- {
- if (space[x] >= registers && (space[column] < registers || space[x] < space[column]))
- {
- column = x;
- }
- }
+ strstr << "[";
+ strstr << i;
+ strstr << "]";
+}
- if (space[column] >= registers)
- {
- for (int r = 0; r < maxVaryingVectors; r++)
- {
- if (!packing[r][column])
- {
- varying->registerIndex = r;
- varying->columnIndex = column;
+const std::string VERTEX_ATTRIBUTE_STUB_STRING = "@@ VERTEX ATTRIBUTES @@";
+const std::string PIXEL_OUTPUT_STUB_STRING = "@@ PIXEL OUTPUT @@";
+} // anonymous namespace
- for (int y = r; y < r + registers; y++)
- {
- packing[y][column] = &*varying;
- }
+std::string GetVaryingSemantic(int majorShaderModel, bool programUsesPointSize)
+{
+ // SM3 reserves the TEXCOORD semantic for point sprite texcoords (gl_PointCoord)
+ // In D3D11 we manually compute gl_PointCoord in the GS.
+ return ((programUsesPointSize && majorShaderModel < 4) ? "COLOR" : "TEXCOORD");
+}
- break;
- }
- }
+// DynamicHLSL implementation
- return true;
- }
- }
- else UNREACHABLE();
-
- return false;
+DynamicHLSL::DynamicHLSL(RendererD3D *const renderer) : mRenderer(renderer)
+{
}
-// Packs varyings into generic varying registers, using the algorithm from [OpenGL ES Shading Language 1.00 rev. 17] appendix A section 7 page 111
-// Returns the number of used varying registers, or -1 if unsuccesful
-int DynamicHLSL::packVaryings(InfoLog &infoLog, VaryingPacking packing, ShaderD3D *fragmentShader,
- ShaderD3D *vertexShader, const std::vector<std::string> &transformFeedbackVaryings)
+void DynamicHLSL::generateVaryingHLSL(const VaryingPacking &varyingPacking,
+ std::stringstream &hlslStream) const
{
- // TODO (geofflang): Use context's caps
- const int maxVaryingVectors = mRenderer->getRendererCaps().maxVaryingVectors;
-
- vertexShader->resetVaryingsRegisterAssignment();
- fragmentShader->resetVaryingsRegisterAssignment();
+ std::string varyingSemantic =
+ GetVaryingSemantic(mRenderer->getMajorShaderModel(), varyingPacking.usesPointSize());
- std::set<std::string> packedVaryings;
-
- std::vector<gl::PackedVarying> &fragmentVaryings = fragmentShader->getVaryings();
- std::vector<gl::PackedVarying> &vertexVaryings = vertexShader->getVaryings();
- for (unsigned int varyingIndex = 0; varyingIndex < fragmentVaryings.size(); varyingIndex++)
+ for (const PackedVaryingRegister &registerInfo : varyingPacking.getRegisterList())
{
- PackedVarying *varying = &fragmentVaryings[varyingIndex];
-
- // Do not assign registers to built-in or unreferenced varyings
- if (varying->isBuiltIn() || !varying->staticUse)
- {
- continue;
- }
-
- if (packVarying(varying, maxVaryingVectors, packing))
- {
- packedVaryings.insert(varying->name);
- }
- else
- {
- infoLog.append("Could not pack varying %s", varying->name.c_str());
- return -1;
- }
- }
+ const auto &varying = *registerInfo.packedVarying->varying;
+ ASSERT(!varying.isStruct());
- for (unsigned int feedbackVaryingIndex = 0; feedbackVaryingIndex < transformFeedbackVaryings.size(); feedbackVaryingIndex++)
- {
- const std::string &transformFeedbackVarying = transformFeedbackVaryings[feedbackVaryingIndex];
+ // TODO: Add checks to ensure D3D interpolation modifiers don't result in too many
+ // registers being used.
+ // For example, if there are N registers, and we have N vec3 varyings and 1 float
+ // varying, then D3D will pack them into N registers.
+ // If the float varying has the 'nointerpolation' modifier on it then we would need
+ // N + 1 registers, and D3D compilation will fail.
- if (transformFeedbackVarying == "gl_Position" || transformFeedbackVarying == "gl_PointSize")
+ switch (registerInfo.packedVarying->interpolation)
{
- // do not pack builtin XFB varyings
- continue;
+ case sh::INTERPOLATION_SMOOTH:
+ hlslStream << " ";
+ break;
+ case sh::INTERPOLATION_FLAT:
+ hlslStream << " nointerpolation ";
+ break;
+ case sh::INTERPOLATION_CENTROID:
+ hlslStream << " centroid ";
+ break;
+ default:
+ UNREACHABLE();
}
- if (packedVaryings.find(transformFeedbackVarying) == packedVaryings.end())
- {
- bool found = false;
- for (unsigned int varyingIndex = 0; varyingIndex < vertexVaryings.size(); varyingIndex++)
- {
- PackedVarying *varying = &vertexVaryings[varyingIndex];
- if (transformFeedbackVarying == varying->name)
- {
- if (!packVarying(varying, maxVaryingVectors, packing))
- {
- infoLog.append("Could not pack varying %s", varying->name.c_str());
- return -1;
- }
-
- found = true;
- break;
- }
- }
-
- if (!found)
- {
- infoLog.append("Transform feedback varying %s does not exist in the vertex shader.", transformFeedbackVarying.c_str());
- return -1;
- }
- }
- }
-
- // Return the number of used registers
- int registers = 0;
-
- for (int r = 0; r < maxVaryingVectors; r++)
- {
- if (packing[r][0] || packing[r][1] || packing[r][2] || packing[r][3])
- {
- registers++;
- }
+ GLenum transposedType = gl::TransposeMatrixType(varying.type);
+ GLenum componentType = gl::VariableComponentType(transposedType);
+ int columnCount = gl::VariableColumnCount(transposedType);
+ hlslStream << HLSLComponentTypeString(componentType, columnCount);
+ unsigned int semanticIndex = registerInfo.semanticIndex;
+ hlslStream << " v" << semanticIndex << " : " << varyingSemantic << semanticIndex << ";\n";
}
-
- return registers;
}
-std::string DynamicHLSL::generateVaryingHLSL(const ShaderD3D *shader) const
+std::string DynamicHLSL::generateVertexShaderForInputLayout(
+ const std::string &sourceShader,
+ const InputLayout &inputLayout,
+ const std::vector<sh::Attribute> &shaderAttributes) const
{
- std::string varyingSemantic = getVaryingSemantic(shader->mUsesPointSize);
- std::string varyingHLSL;
-
- const std::vector<gl::PackedVarying> &varyings = shader->getVaryings();
+ std::stringstream structStream;
+ std::stringstream initStream;
- for (unsigned int varyingIndex = 0; varyingIndex < varyings.size(); varyingIndex++)
- {
- const PackedVarying &varying = varyings[varyingIndex];
- if (varying.registerAssigned())
- {
- ASSERT(!varying.isBuiltIn());
- GLenum transposedType = TransposeMatrixType(varying.type);
- int variableRows = (varying.isStruct() ? 1 : VariableRowCount(transposedType));
-
- for (unsigned int elementIndex = 0; elementIndex < varying.elementCount(); elementIndex++)
- {
- for (int row = 0; row < variableRows; row++)
- {
- // TODO: Add checks to ensure D3D interpolation modifiers don't result in too many registers being used.
- // For example, if there are N registers, and we have N vec3 varyings and 1 float varying, then D3D will pack them into N registers.
- // If the float varying has the 'nointerpolation' modifier on it then we would need N + 1 registers, and D3D compilation will fail.
-
- switch (varying.interpolation)
- {
- case sh::INTERPOLATION_SMOOTH: varyingHLSL += " "; break;
- case sh::INTERPOLATION_FLAT: varyingHLSL += " nointerpolation "; break;
- case sh::INTERPOLATION_CENTROID: varyingHLSL += " centroid "; break;
- default: UNREACHABLE();
- }
-
- unsigned int semanticIndex = elementIndex * variableRows +
- varying.columnIndex * mRenderer->getRendererCaps().maxVaryingVectors +
- varying.registerIndex + row;
- std::string n = Str(semanticIndex);
-
- std::string typeString;
-
- if (varying.isStruct())
- {
- // TODO(jmadill): pass back translated name from the shader translator
- typeString = decorateVariable(varying.structName);
- }
- else
- {
- GLenum componentType = VariableComponentType(transposedType);
- int columnCount = VariableColumnCount(transposedType);
- typeString = HLSLComponentTypeString(componentType, columnCount);
- }
- varyingHLSL += typeString + " v" + n + " : " + varyingSemantic + n + ";\n";
- }
- }
- }
- }
-
- return varyingHLSL;
-}
+ structStream << "struct VS_INPUT\n"
+ << "{\n";
-std::string DynamicHLSL::generateVertexShaderForInputLayout(const std::string &sourceShader,
- const VertexFormat inputLayout[],
- const sh::Attribute shaderAttributes[]) const
-{
- std::string structHLSL, initHLSL;
-
- int semanticIndex = 0;
+ int semanticIndex = 0;
unsigned int inputIndex = 0;
// If gl_PointSize is used in the shader then pointsprites rendering is expected.
// If the renderer does not support Geometry shaders then Instanced PointSprite emulation
// must be used.
bool usesPointSize = sourceShader.find("GL_USES_POINT_SIZE") != std::string::npos;
- bool useInstancedPointSpriteEmulation = usesPointSize && mRenderer->getWorkarounds().useInstancedPointSpriteEmulation;
+ bool useInstancedPointSpriteEmulation =
+ usesPointSize && mRenderer->getWorkarounds().useInstancedPointSpriteEmulation;
// Instanced PointSprite emulation requires additional entries in the
// VS_INPUT structure to support the vertices that make up the quad vertices.
@@ -402,102 +207,109 @@ std::string DynamicHLSL::generateVertexShaderForInputLayout(const std::string &s
// before per instance data in the shader.
if (useInstancedPointSpriteEmulation)
{
- structHLSL += " float3 spriteVertexPos : SPRITEPOSITION0;\n";
- structHLSL += " float2 spriteTexCoord : SPRITETEXCOORD0;\n";
+ structStream << " float3 spriteVertexPos : SPRITEPOSITION0;\n"
+ << " float2 spriteTexCoord : SPRITETEXCOORD0;\n";
}
- for (unsigned int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
+ for (size_t attributeIndex = 0; attributeIndex < shaderAttributes.size(); ++attributeIndex)
{
const sh::Attribute &shaderAttribute = shaderAttributes[attributeIndex];
if (!shaderAttribute.name.empty())
{
ASSERT(inputIndex < MAX_VERTEX_ATTRIBS);
- const VertexFormat &vertexFormat = inputLayout[inputIndex];
+ VertexFormatType vertexFormatType =
+ inputIndex < inputLayout.size() ? inputLayout[inputIndex] : VERTEX_FORMAT_INVALID;
// HLSL code for input structure
if (IsMatrixType(shaderAttribute.type))
{
// Matrix types are always transposed
- structHLSL += " " + HLSLMatrixTypeString(TransposeMatrixType(shaderAttribute.type));
+ structStream << " "
+ << HLSLMatrixTypeString(TransposeMatrixType(shaderAttribute.type));
}
else
{
- GLenum componentType = mRenderer->getVertexComponentType(vertexFormat);
+ GLenum componentType = mRenderer->getVertexComponentType(vertexFormatType);
if (shaderAttribute.name == "gl_InstanceID")
{
- // The input type of the instance ID in HLSL (uint) differs from the one in ESSL (int).
- structHLSL += " uint";
+ // The input type of the instance ID in HLSL (uint) differs from the one in ESSL
+ // (int).
+ structStream << " uint";
}
else
{
- structHLSL += " " + HLSLComponentTypeString(componentType, VariableComponentCount(shaderAttribute.type));
+ structStream << " " << HLSLComponentTypeString(
+ componentType,
+ VariableComponentCount(shaderAttribute.type));
}
}
- structHLSL += " " + decorateVariable(shaderAttribute.name) + " : ";
+ structStream << " " << decorateVariable(shaderAttribute.name) << " : ";
if (shaderAttribute.name == "gl_InstanceID")
{
- structHLSL += "SV_InstanceID";
+ structStream << "SV_InstanceID";
}
else
{
- structHLSL += "TEXCOORD" + Str(semanticIndex);
+ structStream << "TEXCOORD" << semanticIndex;
semanticIndex += VariableRegisterCount(shaderAttribute.type);
}
- structHLSL += ";\n";
+ structStream << ";\n";
// HLSL code for initialization
- initHLSL += " " + decorateVariable(shaderAttribute.name) + " = ";
+ initStream << " " << decorateVariable(shaderAttribute.name) << " = ";
// Mismatched vertex attribute to vertex input may result in an undefined
// data reinterpretation (eg for pure integer->float, float->pure integer)
// TODO: issue warning with gl debug info extension, when supported
if (IsMatrixType(shaderAttribute.type) ||
- (mRenderer->getVertexConversionType(vertexFormat) & VERTEX_CONVERT_GPU) != 0)
+ (mRenderer->getVertexConversionType(vertexFormatType) & VERTEX_CONVERT_GPU) != 0)
{
- initHLSL += generateAttributeConversionHLSL(vertexFormat, shaderAttribute);
+ initStream << generateAttributeConversionHLSL(vertexFormatType, shaderAttribute);
}
else
{
- initHLSL += "input." + decorateVariable(shaderAttribute.name);
+ initStream << "input." << decorateVariable(shaderAttribute.name);
}
- initHLSL += ";\n";
+ initStream << ";\n";
inputIndex += VariableRowCount(TransposeMatrixType(shaderAttribute.type));
}
}
- std::string replacementHLSL = "struct VS_INPUT\n"
- "{\n" +
- structHLSL +
- "};\n"
- "\n"
- "void initAttributes(VS_INPUT input)\n"
- "{\n" +
- initHLSL +
- "}\n";
+ structStream << "};\n"
+ "\n"
+ "void initAttributes(VS_INPUT input)\n"
+ "{\n"
+ << initStream.str() << "}\n";
std::string vertexHLSL(sourceShader);
size_t copyInsertionPos = vertexHLSL.find(VERTEX_ATTRIBUTE_STUB_STRING);
- vertexHLSL.replace(copyInsertionPos, VERTEX_ATTRIBUTE_STUB_STRING.length(), replacementHLSL);
+ vertexHLSL.replace(copyInsertionPos, VERTEX_ATTRIBUTE_STUB_STRING.length(), structStream.str());
return vertexHLSL;
}
-std::string DynamicHLSL::generatePixelShaderForOutputSignature(const std::string &sourceShader, const std::vector<PixelShaderOutputVariable> &outputVariables,
- bool usesFragDepth, const std::vector<GLenum> &outputLayout) const
+std::string DynamicHLSL::generatePixelShaderForOutputSignature(
+ const std::string &sourceShader,
+ const std::vector<PixelShaderOutputVariable> &outputVariables,
+ bool usesFragDepth,
+ const std::vector<GLenum> &outputLayout) const
{
- const int shaderModel = mRenderer->getMajorShaderModel();
+ const int shaderModel = mRenderer->getMajorShaderModel();
std::string targetSemantic = (shaderModel >= 4) ? "SV_TARGET" : "COLOR";
- std::string depthSemantic = (shaderModel >= 4) ? "SV_Depth" : "DEPTH";
+ std::string depthSemantic = (shaderModel >= 4) ? "SV_Depth" : "DEPTH";
+
+ std::stringstream declarationStream;
+ std::stringstream copyStream;
- std::string declarationHLSL;
- std::string copyHLSL;
+ declarationStream << "struct PS_OUTPUT\n"
+ "{\n";
for (size_t layoutIndex = 0; layoutIndex < outputLayout.size(); ++layoutIndex)
{
@@ -507,703 +319,680 @@ std::string DynamicHLSL::generatePixelShaderForOutputSignature(const std::string
{
unsigned int location = (binding - GL_COLOR_ATTACHMENT0);
- const PixelShaderOutputVariable *outputVariable = FindOutputAtLocation(outputVariables, location);
+ const PixelShaderOutputVariable *outputVariable =
+ FindOutputAtLocation(outputVariables, location);
// OpenGL ES 3.0 spec $4.2.1
- // If [...] not all user-defined output variables are written, the values of fragment colors
+ // If [...] not all user-defined output variables are written, the values of fragment
+ // colors
// corresponding to unwritten variables are similarly undefined.
if (outputVariable)
{
- declarationHLSL += " " + HLSLTypeString(outputVariable->type) + " " + outputVariable->name +
- " : " + targetSemantic + Str(layoutIndex) + ";\n";
+ declarationStream << " " + HLSLTypeString(outputVariable->type) << " "
+ << outputVariable->name << " : " << targetSemantic
+ << static_cast<int>(layoutIndex) << ";\n";
- copyHLSL += " output." + outputVariable->name + " = " + outputVariable->source + ";\n";
+ copyStream << " output." << outputVariable->name << " = "
+ << outputVariable->source << ";\n";
}
}
}
if (usesFragDepth)
{
- declarationHLSL += " float gl_Depth : " + depthSemantic + ";\n";
- copyHLSL += " output.gl_Depth = gl_Depth; \n";
+ declarationStream << " float gl_Depth : " << depthSemantic << ";\n";
+ copyStream << " output.gl_Depth = gl_Depth; \n";
}
- std::string replacementHLSL = "struct PS_OUTPUT\n"
- "{\n" +
- declarationHLSL +
- "};\n"
- "\n"
- "PS_OUTPUT generateOutput()\n"
- "{\n"
- " PS_OUTPUT output;\n" +
- copyHLSL +
- " return output;\n"
- "}\n";
+ declarationStream << "};\n"
+ "\n"
+ "PS_OUTPUT generateOutput()\n"
+ "{\n"
+ " PS_OUTPUT output;\n"
+ << copyStream.str() << " return output;\n"
+ "}\n";
std::string pixelHLSL(sourceShader);
size_t outputInsertionPos = pixelHLSL.find(PIXEL_OUTPUT_STUB_STRING);
- pixelHLSL.replace(outputInsertionPos, PIXEL_OUTPUT_STUB_STRING.length(), replacementHLSL);
+ pixelHLSL.replace(outputInsertionPos, PIXEL_OUTPUT_STUB_STRING.length(),
+ declarationStream.str());
return pixelHLSL;
}
-std::string DynamicHLSL::getVaryingSemantic(bool pointSize) const
-{
- // SM3 reserves the TEXCOORD semantic for point sprite texcoords (gl_PointCoord)
- // In D3D11 we manually compute gl_PointCoord in the GS.
- int shaderModel = mRenderer->getMajorShaderModel();
- return ((pointSize && shaderModel < 4) ? "COLOR" : "TEXCOORD");
-}
-
-struct DynamicHLSL::SemanticInfo
-{
- struct BuiltinInfo
- {
- BuiltinInfo()
- : enabled(false),
- index(0),
- systemValue(false)
- {}
-
- bool enabled;
- std::string semantic;
- unsigned int index;
- bool systemValue;
-
- std::string str() const
- {
- return (systemValue ? semantic : (semantic + Str(index)));
- }
-
- void enableSystem(const std::string &systemValueSemantic)
- {
- enabled = true;
- semantic = systemValueSemantic;
- systemValue = true;
- }
-
- void enable(const std::string &semanticVal, unsigned int indexVal)
- {
- enabled = true;
- semantic = semanticVal;
- index = indexVal;
- }
- };
-
- BuiltinInfo dxPosition;
- BuiltinInfo glPosition;
- BuiltinInfo glFragCoord;
- BuiltinInfo glPointCoord;
- BuiltinInfo glPointSize;
-};
-
-DynamicHLSL::SemanticInfo DynamicHLSL::getSemanticInfo(int startRegisters, bool position, bool fragCoord,
- bool pointCoord, bool pointSize, bool pixelShader) const
+void DynamicHLSL::generateVaryingLinkHLSL(ShaderType shaderType,
+ const VaryingPacking &varyingPacking,
+ std::stringstream &linkStream) const
{
- SemanticInfo info;
- bool hlsl4 = (mRenderer->getMajorShaderModel() >= 4);
- const std::string &varyingSemantic = getVaryingSemantic(pointSize);
-
- int reservedRegisterIndex = startRegisters;
+ const auto &builtins = varyingPacking.builtins(shaderType);
+ ASSERT(builtins.dxPosition.enabled);
+ linkStream << "{\n"
+ << " float4 dx_Position : " << builtins.dxPosition.str() << ";\n";
- if (hlsl4)
+ if (builtins.glPosition.enabled)
{
- info.dxPosition.enableSystem("SV_Position");
- }
- else if (pixelShader)
- {
- info.dxPosition.enableSystem("VPOS");
- }
- else
- {
- info.dxPosition.enableSystem("POSITION");
- }
-
- if (position)
- {
- info.glPosition.enable(varyingSemantic, reservedRegisterIndex++);
- }
-
- if (fragCoord)
- {
- info.glFragCoord.enable(varyingSemantic, reservedRegisterIndex++);
- }
-
- if (pointCoord)
- {
- // SM3 reserves the TEXCOORD semantic for point sprite texcoords (gl_PointCoord)
- // In D3D11 we manually compute gl_PointCoord in the GS.
- if (hlsl4)
- {
- info.glPointCoord.enable(varyingSemantic, reservedRegisterIndex++);
- }
- else
- {
- info.glPointCoord.enable("TEXCOORD", 0);
- }
- }
-
- // Special case: do not include PSIZE semantic in HLSL 3 pixel shaders
- if (pointSize && (!pixelShader || hlsl4))
- {
- info.glPointSize.enableSystem("PSIZE");
+ linkStream << " float4 gl_Position : " << builtins.glPosition.str() << ";\n";
}
- return info;
-}
-
-std::string DynamicHLSL::generateVaryingLinkHLSL(const SemanticInfo &info, const std::string &varyingHLSL) const
-{
- std::string linkHLSL = "{\n";
-
- ASSERT(info.dxPosition.enabled);
- linkHLSL += " float4 dx_Position : " + info.dxPosition.str() + ";\n";
-
- if (info.glPosition.enabled)
- {
- linkHLSL += " float4 gl_Position : " + info.glPosition.str() + ";\n";
- }
-
- if (info.glFragCoord.enabled)
- {
- linkHLSL += " float4 gl_FragCoord : " + info.glFragCoord.str() + ";\n";
- }
-
- if (info.glPointCoord.enabled)
- {
- linkHLSL += " float2 gl_PointCoord : " + info.glPointCoord.str() + ";\n";
- }
-
- if (info.glPointSize.enabled)
- {
- linkHLSL += " float gl_PointSize : " + info.glPointSize.str() + ";\n";
- }
-
- // Do this after glPointSize, to potentially combine gl_PointCoord and gl_PointSize into the same register.
- linkHLSL += varyingHLSL;
-
- linkHLSL += "};\n";
-
- return linkHLSL;
-}
-
-void DynamicHLSL::storeBuiltinLinkedVaryings(const SemanticInfo &info,
- std::vector<LinkedVarying> *linkedVaryings) const
-{
- if (info.glPosition.enabled)
+ if (builtins.glFragCoord.enabled)
{
- linkedVaryings->push_back(LinkedVarying("gl_Position", GL_FLOAT_VEC4, 1, info.glPosition.semantic,
- info.glPosition.index, 1));
+ linkStream << " float4 gl_FragCoord : " << builtins.glFragCoord.str() << ";\n";
}
- if (info.glFragCoord.enabled)
+ if (builtins.glPointCoord.enabled)
{
- linkedVaryings->push_back(LinkedVarying("gl_FragCoord", GL_FLOAT_VEC4, 1, info.glFragCoord.semantic,
- info.glFragCoord.index, 1));
+ linkStream << " float2 gl_PointCoord : " << builtins.glPointCoord.str() << ";\n";
}
- if (info.glPointSize.enabled)
+ if (builtins.glPointSize.enabled)
{
- linkedVaryings->push_back(LinkedVarying("gl_PointSize", GL_FLOAT, 1, "PSIZE", 0, 1));
+ linkStream << " float gl_PointSize : " << builtins.glPointSize.str() << ";\n";
}
-}
-
-void DynamicHLSL::storeUserLinkedVaryings(const ShaderD3D *vertexShader,
- std::vector<LinkedVarying> *linkedVaryings) const
-{
- const std::string &varyingSemantic = getVaryingSemantic(vertexShader->mUsesPointSize);
- const std::vector<PackedVarying> &varyings = vertexShader->getVaryings();
- for (unsigned int varyingIndex = 0; varyingIndex < varyings.size(); varyingIndex++)
- {
- const PackedVarying &varying = varyings[varyingIndex];
-
- if (varying.registerAssigned())
- {
- ASSERT(!varying.isBuiltIn());
- GLenum transposedType = TransposeMatrixType(varying.type);
- int variableRows = (varying.isStruct() ? 1 : VariableRowCount(transposedType));
+ // Do this after glPointSize, to potentially combine gl_PointCoord and gl_PointSize into the
+ // same register.
+ generateVaryingHLSL(varyingPacking, linkStream);
- linkedVaryings->push_back(LinkedVarying(varying.name, varying.type, varying.elementCount(),
- varyingSemantic, varying.registerIndex,
- variableRows * varying.elementCount()));
- }
- }
+ linkStream << "};\n";
}
-bool DynamicHLSL::generateShaderLinkHLSL(const gl::Data &data, InfoLog &infoLog, int registers,
- const VaryingPacking packing,
- std::string &pixelHLSL, std::string &vertexHLSL,
- ShaderD3D *fragmentShader, ShaderD3D *vertexShader,
- const std::vector<std::string> &transformFeedbackVaryings,
- std::vector<LinkedVarying> *linkedVaryings,
- std::map<int, VariableLocation> *programOutputVars,
- std::vector<PixelShaderOutputVariable> *outPixelShaderKey,
- bool *outUsesFragDepth) const
+bool DynamicHLSL::generateShaderLinkHLSL(const gl::Data &data,
+ const gl::Program::Data &programData,
+ const ProgramD3DMetadata &programMetadata,
+ const VaryingPacking &varyingPacking,
+ std::string *pixelHLSL,
+ std::string *vertexHLSL) const
{
- if (pixelHLSL.empty() || vertexHLSL.empty())
- {
- return false;
- }
+ ASSERT(pixelHLSL->empty() && vertexHLSL->empty());
- bool usesMRT = fragmentShader->mUsesMultipleRenderTargets;
- bool usesFragColor = fragmentShader->mUsesFragColor;
- bool usesFragData = fragmentShader->mUsesFragData;
- bool usesFragCoord = fragmentShader->mUsesFragCoord;
- bool usesPointCoord = fragmentShader->mUsesPointCoord;
- bool usesPointSize = vertexShader->mUsesPointSize;
- bool useInstancedPointSpriteEmulation = usesPointSize && mRenderer->getWorkarounds().useInstancedPointSpriteEmulation;
+ const gl::Shader *vertexShaderGL = programData.getAttachedVertexShader();
+ const ShaderD3D *vertexShader = GetImplAs<ShaderD3D>(vertexShaderGL);
+ const gl::Shader *fragmentShaderGL = programData.getAttachedFragmentShader();
+ const ShaderD3D *fragmentShader = GetImplAs<ShaderD3D>(fragmentShaderGL);
+ const int shaderModel = mRenderer->getMajorShaderModel();
- if (usesFragColor && usesFragData)
- {
- infoLog.append("Cannot use both gl_FragColor and gl_FragData in the same fragment shader.");
- return false;
- }
-
- // Write the HLSL input/output declarations
- const int shaderModel = mRenderer->getMajorShaderModel();
- const int registersNeeded = registers + (usesFragCoord ? 1 : 0) + (usesPointCoord ? 1 : 0);
-
- // Two cases when writing to gl_FragColor and using ESSL 1.0:
- // - with a 3.0 context, the output color is copied to channel 0
- // - with a 2.0 context, the output color is broadcast to all channels
- const bool broadcast = (fragmentShader->mUsesFragColor && data.clientVersion < 3);
- const unsigned int numRenderTargets = (broadcast || usesMRT ? data.caps->maxDrawBuffers : 1);
-
- // gl_Position only needs to be outputted from the vertex shader if transform feedback is active.
- // This isn't supported on D3D11 Feature Level 9_3, so we don't output gl_Position from the vertex shader in this case.
- // This saves us 1 output vector.
- bool outputPositionFromVS = !(shaderModel >= 4 && mRenderer->getShaderModelSuffix() != "");
-
- int shaderVersion = vertexShader->getShaderVersion();
-
- if (static_cast<GLuint>(registersNeeded) > data.caps->maxVaryingVectors)
- {
- infoLog.append("No varying registers left to support gl_FragCoord/gl_PointCoord");
- return false;
- }
+ // usesViewScale() isn't supported in the D3D9 renderer
+ ASSERT(shaderModel >= 4 || !programMetadata.usesViewScale());
- const std::string &varyingHLSL = generateVaryingHLSL(vertexShader);
+ bool useInstancedPointSpriteEmulation =
+ programMetadata.usesPointSize() &&
+ mRenderer->getWorkarounds().useInstancedPointSpriteEmulation;
- // Instanced PointSprite emulation requires that gl_PointCoord is present in the vertex shader VS_OUTPUT
- // structure to ensure compatibility with the generated PS_INPUT of the pixel shader.
- // GeometryShader PointSprite emulation does not require this additional entry because the
- // GS_OUTPUT of the Geometry shader contains the pointCoord value and already matches the PS_INPUT of the
- // generated pixel shader.
- // The Geometry Shader point sprite implementation needs gl_PointSize to be in VS_OUTPUT and GS_INPUT.
- // Instanced point sprites doesn't need gl_PointSize in VS_OUTPUT.
- const SemanticInfo &vertexSemantics = getSemanticInfo(registers, outputPositionFromVS,
- usesFragCoord, (useInstancedPointSpriteEmulation && usesPointCoord),
- (!useInstancedPointSpriteEmulation && usesPointSize), false);
+ // Validation done in the compiler
+ ASSERT(!fragmentShader->usesFragColor() || !fragmentShader->usesFragData());
- storeUserLinkedVaryings(vertexShader, linkedVaryings);
- storeBuiltinLinkedVaryings(vertexSemantics, linkedVaryings);
+ std::stringstream vertexStream;
+ vertexStream << vertexShaderGL->getTranslatedSource();
// Instanced PointSprite emulation requires additional entries originally generated in the
- // GeometryShader HLSL. These include pointsize clamp values.
+ // GeometryShader HLSL. These include pointsize clamp values.
if (useInstancedPointSpriteEmulation)
{
- vertexHLSL += "static float minPointSize = " + Str((int)mRenderer->getRendererCaps().minAliasedPointSize) + ".0f;\n"
- "static float maxPointSize = " + Str((int)mRenderer->getRendererCaps().maxAliasedPointSize) + ".0f;\n";
+ vertexStream << "static float minPointSize = "
+ << static_cast<int>(data.caps->minAliasedPointSize) << ".0f;\n"
+ << "static float maxPointSize = "
+ << static_cast<int>(data.caps->maxAliasedPointSize) << ".0f;\n";
}
// Add stub string to be replaced when shader is dynamically defined by its layout
- vertexHLSL += "\n" + VERTEX_ATTRIBUTE_STUB_STRING + "\n"
- "struct VS_OUTPUT\n" + generateVaryingLinkHLSL(vertexSemantics, varyingHLSL) + "\n"
- "VS_OUTPUT main(VS_INPUT input)\n"
- "{\n"
- " initAttributes(input);\n";
+ vertexStream << "\n" << VERTEX_ATTRIBUTE_STUB_STRING + "\n";
+
+ // Write the HLSL input/output declarations
+ vertexStream << "struct VS_OUTPUT\n";
+ generateVaryingLinkHLSL(SHADER_VERTEX, varyingPacking, vertexStream);
+ vertexStream << "\n"
+ << "VS_OUTPUT main(VS_INPUT input)\n"
+ << "{\n"
+ << " initAttributes(input);\n";
if (vertexShader->usesDeferredInit())
{
- vertexHLSL += "\n"
- " initializeDeferredGlobals();\n";
+ vertexStream << "\n"
+ << " initializeDeferredGlobals();\n";
}
- vertexHLSL += "\n"
- " gl_main();\n"
- "\n"
- " VS_OUTPUT output;\n";
+ vertexStream << "\n"
+ << " gl_main();\n"
+ << "\n"
+ << " VS_OUTPUT output;\n";
+
+ const auto &vertexBuiltins = varyingPacking.builtins(SHADER_VERTEX);
- if (outputPositionFromVS)
+ if (vertexBuiltins.glPosition.enabled)
{
- vertexHLSL += " output.gl_Position = gl_Position;\n";
+ vertexStream << " output.gl_Position = gl_Position;\n";
}
// On D3D9 or D3D11 Feature Level 9, we need to emulate large viewports using dx_ViewAdjust.
- if (shaderModel >= 4 && mRenderer->getShaderModelSuffix() == "")
+ if (shaderModel >= 4 && mRenderer->getShaderModelSuffix() == "")
{
- vertexHLSL += " output.dx_Position.x = gl_Position.x;\n"
- " output.dx_Position.y = -gl_Position.y;\n"
- " output.dx_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
- " output.dx_Position.w = gl_Position.w;\n";
+ vertexStream << " output.dx_Position.x = gl_Position.x;\n";
+
+ if (programMetadata.usesViewScale())
+ {
+ // This code assumes that dx_ViewScale.y = -1.0f when rendering to texture, and +1.0f
+ // when rendering to the default framebuffer. No other values are valid.
+ vertexStream << " output.dx_Position.y = dx_ViewScale.y * gl_Position.y;\n";
+ }
+ else
+ {
+ vertexStream << " output.dx_Position.y = - gl_Position.y;\n";
+ }
+
+ vertexStream << " output.dx_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
+ << " output.dx_Position.w = gl_Position.w;\n";
}
else
{
- vertexHLSL += " output.dx_Position.x = gl_Position.x * dx_ViewAdjust.z + dx_ViewAdjust.x * gl_Position.w;\n"
- " output.dx_Position.y = -(gl_Position.y * dx_ViewAdjust.w + dx_ViewAdjust.y * gl_Position.w);\n"
- " output.dx_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
- " output.dx_Position.w = gl_Position.w;\n";
+ vertexStream << " output.dx_Position.x = gl_Position.x * dx_ViewAdjust.z + "
+ "dx_ViewAdjust.x * gl_Position.w;\n";
+
+ // If usesViewScale() is true and we're using the D3D11 renderer via Feature Level 9_*,
+ // then we need to multiply the gl_Position.y by the viewScale.
+ // usesViewScale() isn't supported when using the D3D9 renderer.
+ if (programMetadata.usesViewScale() &&
+ (shaderModel >= 4 && mRenderer->getShaderModelSuffix() != ""))
+ {
+ vertexStream << " output.dx_Position.y = dx_ViewScale.y * (gl_Position.y * "
+ "dx_ViewAdjust.w + dx_ViewAdjust.y * gl_Position.w);\n";
+ }
+ else
+ {
+ vertexStream << " output.dx_Position.y = -(gl_Position.y * dx_ViewAdjust.w + "
+ "dx_ViewAdjust.y * gl_Position.w);\n";
+ }
+
+ vertexStream << " output.dx_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
+ << " output.dx_Position.w = gl_Position.w;\n";
}
// We don't need to output gl_PointSize if we use are emulating point sprites via instancing.
- if (usesPointSize && shaderModel >= 3 && !useInstancedPointSpriteEmulation)
+ if (vertexBuiltins.glPointSize.enabled)
{
- vertexHLSL += " output.gl_PointSize = gl_PointSize;\n";
+ vertexStream << " output.gl_PointSize = gl_PointSize;\n";
}
- if (usesFragCoord)
+ if (vertexBuiltins.glFragCoord.enabled)
{
- vertexHLSL += " output.gl_FragCoord = gl_Position;\n";
+ vertexStream << " output.gl_FragCoord = gl_Position;\n";
}
- const std::vector<PackedVarying> &vertexVaryings = vertexShader->getVaryings();
- for (unsigned int vertVaryingIndex = 0; vertVaryingIndex < vertexVaryings.size(); vertVaryingIndex++)
+ for (const PackedVaryingRegister &registerInfo : varyingPacking.getRegisterList())
{
- const PackedVarying &varying = vertexVaryings[vertVaryingIndex];
- if (varying.registerAssigned())
- {
- for (unsigned int elementIndex = 0; elementIndex < varying.elementCount(); elementIndex++)
- {
- int variableRows = (varying.isStruct() ? 1 : VariableRowCount(TransposeMatrixType(varying.type)));
+ const auto &packedVarying = *registerInfo.packedVarying;
+ const auto &varying = *packedVarying.varying;
+ ASSERT(!varying.isStruct());
- for (int row = 0; row < variableRows; row++)
- {
- int r = varying.registerIndex + varying.columnIndex * data.caps->maxVaryingVectors + elementIndex * variableRows + row;
- vertexHLSL += " output.v" + Str(r);
+ vertexStream << " output.v" << registerInfo.semanticIndex << " = ";
- vertexHLSL += " = _" + varying.name;
+ if (packedVarying.isStructField())
+ {
+ vertexStream << decorateVariable(packedVarying.parentStructName) << ".";
+ }
- if (varying.isArray())
- {
- vertexHLSL += ArrayString(elementIndex);
- }
+ vertexStream << decorateVariable(varying.name);
- if (variableRows > 1)
- {
- vertexHLSL += ArrayString(row);
- }
+ if (varying.isArray())
+ {
+ WriteArrayString(vertexStream, registerInfo.varyingArrayIndex);
+ }
- vertexHLSL += ";\n";
- }
- }
+ if (VariableRowCount(varying.type) > 1)
+ {
+ WriteArrayString(vertexStream, registerInfo.varyingRowIndex);
}
+
+ vertexStream << ";\n";
}
// Instanced PointSprite emulation requires additional entries to calculate
// the final output vertex positions of the quad that represents each sprite.
if (useInstancedPointSpriteEmulation)
{
- vertexHLSL += "\n"
- " gl_PointSize = clamp(gl_PointSize, minPointSize, maxPointSize);\n"
- " output.dx_Position.xyz += float3(input.spriteVertexPos.x * gl_PointSize / (dx_ViewCoords.x*2), input.spriteVertexPos.y * gl_PointSize / (dx_ViewCoords.y*2), input.spriteVertexPos.z) * output.dx_Position.w;\n";
+ vertexStream << "\n"
+ << " gl_PointSize = clamp(gl_PointSize, minPointSize, maxPointSize);\n";
+
+ vertexStream << " output.dx_Position.x += (input.spriteVertexPos.x * gl_PointSize / "
+ "(dx_ViewCoords.x*2)) * output.dx_Position.w;";
- if (usesPointCoord)
+ if (programMetadata.usesViewScale())
{
- vertexHLSL += "\n"
- " output.gl_PointCoord = input.spriteTexCoord;\n";
+ // Multiply by ViewScale to invert the rendering when appropriate
+ vertexStream << " output.dx_Position.y += (-dx_ViewScale.y * "
+ "input.spriteVertexPos.y * gl_PointSize / (dx_ViewCoords.y*2)) * "
+ "output.dx_Position.w;";
}
- }
-
- vertexHLSL += "\n"
- " return output;\n"
- "}\n";
-
- const SemanticInfo &pixelSemantics = getSemanticInfo(registers, outputPositionFromVS, usesFragCoord, usesPointCoord,
- (!useInstancedPointSpriteEmulation && usesPointSize), true);
-
- pixelHLSL += "struct PS_INPUT\n" + generateVaryingLinkHLSL(pixelSemantics, varyingHLSL) + "\n";
-
- if (shaderVersion < 300)
- {
- for (unsigned int renderTargetIndex = 0; renderTargetIndex < numRenderTargets; renderTargetIndex++)
+ else
{
- PixelShaderOutputVariable outputKeyVariable;
- outputKeyVariable.type = GL_FLOAT_VEC4;
- outputKeyVariable.name = "gl_Color" + Str(renderTargetIndex);
- outputKeyVariable.source = broadcast ? "gl_Color[0]" : "gl_Color[" + Str(renderTargetIndex) + "]";
- outputKeyVariable.outputIndex = renderTargetIndex;
-
- outPixelShaderKey->push_back(outputKeyVariable);
+ vertexStream << " output.dx_Position.y += (input.spriteVertexPos.y * gl_PointSize / "
+ "(dx_ViewCoords.y*2)) * output.dx_Position.w;";
}
- *outUsesFragDepth = fragmentShader->mUsesFragDepth;
- }
- else
- {
- defineOutputVariables(fragmentShader, programOutputVars);
+ vertexStream
+ << " output.dx_Position.z += input.spriteVertexPos.z * output.dx_Position.w;\n";
- const std::vector<sh::Attribute> &shaderOutputVars = fragmentShader->getActiveOutputVariables();
- for (auto locationIt = programOutputVars->begin(); locationIt != programOutputVars->end(); locationIt++)
+ if (programMetadata.usesPointCoord())
{
- const VariableLocation &outputLocation = locationIt->second;
- const sh::ShaderVariable &outputVariable = shaderOutputVars[outputLocation.index];
- const std::string &variableName = "out_" + outputLocation.name;
- const std::string &elementString = (outputLocation.element == GL_INVALID_INDEX ? "" : Str(outputLocation.element));
-
- ASSERT(outputVariable.staticUse);
-
- PixelShaderOutputVariable outputKeyVariable;
- outputKeyVariable.type = outputVariable.type;
- outputKeyVariable.name = variableName + elementString;
- outputKeyVariable.source = variableName + ArrayString(outputLocation.element);
- outputKeyVariable.outputIndex = locationIt->first;
-
- outPixelShaderKey->push_back(outputKeyVariable);
+ vertexStream << "\n"
+ << " output.gl_PointCoord = input.spriteTexCoord;\n";
}
+ }
- *outUsesFragDepth = false;
+ // Renderers that enable instanced pointsprite emulation require the vertex shader output member
+ // gl_PointCoord to be set to a default value if used without gl_PointSize. 0.5,0.5 is the same
+ // default value used in the generated pixel shader.
+ if (programMetadata.usesInsertedPointCoordValue())
+ {
+ ASSERT(!useInstancedPointSpriteEmulation);
+ vertexStream << "\n"
+ << " output.gl_PointCoord = float2(0.5, 0.5);\n";
}
- pixelHLSL += PIXEL_OUTPUT_STUB_STRING + "\n";
+ vertexStream << "\n"
+ << " return output;\n"
+ << "}\n";
+
+ std::stringstream pixelStream;
+ pixelStream << fragmentShaderGL->getTranslatedSource();
+ pixelStream << "struct PS_INPUT\n";
+ generateVaryingLinkHLSL(SHADER_PIXEL, varyingPacking, pixelStream);
+ pixelStream << "\n";
+
+ pixelStream << PIXEL_OUTPUT_STUB_STRING + "\n";
- if (fragmentShader->mUsesFrontFacing)
+ if (fragmentShader->usesFrontFacing())
{
if (shaderModel >= 4)
{
- pixelHLSL += "PS_OUTPUT main(PS_INPUT input, bool isFrontFace : SV_IsFrontFace)\n"
- "{\n";
+ pixelStream << "PS_OUTPUT main(PS_INPUT input, bool isFrontFace : SV_IsFrontFace)\n"
+ << "{\n";
}
else
{
- pixelHLSL += "PS_OUTPUT main(PS_INPUT input, float vFace : VFACE)\n"
- "{\n";
+ pixelStream << "PS_OUTPUT main(PS_INPUT input, float vFace : VFACE)\n"
+ << "{\n";
}
}
else
{
- pixelHLSL += "PS_OUTPUT main(PS_INPUT input)\n"
- "{\n";
+ pixelStream << "PS_OUTPUT main(PS_INPUT input)\n"
+ << "{\n";
}
- if (usesFragCoord)
+ const auto &pixelBuiltins = varyingPacking.builtins(SHADER_PIXEL);
+
+ if (pixelBuiltins.glFragCoord.enabled)
{
- pixelHLSL += " float rhw = 1.0 / input.gl_FragCoord.w;\n";
+ pixelStream << " float rhw = 1.0 / input.gl_FragCoord.w;\n";
// Certain Shader Models (4_0+ and 3_0) allow reading from dx_Position in the pixel shader.
- // Other Shader Models (4_0_level_9_3 and 2_x) don't support this, so we emulate it using dx_ViewCoords.
+ // Other Shader Models (4_0_level_9_3 and 2_x) don't support this, so we emulate it using
+ // dx_ViewCoords.
if (shaderModel >= 4 && mRenderer->getShaderModelSuffix() == "")
{
- pixelHLSL += " gl_FragCoord.x = input.dx_Position.x;\n"
- " gl_FragCoord.y = input.dx_Position.y;\n";
+ pixelStream << " gl_FragCoord.x = input.dx_Position.x;\n"
+ << " gl_FragCoord.y = input.dx_Position.y;\n";
}
else if (shaderModel == 3)
{
- pixelHLSL += " gl_FragCoord.x = input.dx_Position.x + 0.5;\n"
- " gl_FragCoord.y = input.dx_Position.y + 0.5;\n";
+ pixelStream << " gl_FragCoord.x = input.dx_Position.x + 0.5;\n"
+ << " gl_FragCoord.y = input.dx_Position.y + 0.5;\n";
}
else
{
- // dx_ViewCoords contains the viewport width/2, height/2, center.x and center.y. See Renderer::setViewport()
- pixelHLSL += " gl_FragCoord.x = (input.gl_FragCoord.x * rhw) * dx_ViewCoords.x + dx_ViewCoords.z;\n"
- " gl_FragCoord.y = (input.gl_FragCoord.y * rhw) * dx_ViewCoords.y + dx_ViewCoords.w;\n";
+ // dx_ViewCoords contains the viewport width/2, height/2, center.x and center.y. See
+ // Renderer::setViewport()
+ pixelStream << " gl_FragCoord.x = (input.gl_FragCoord.x * rhw) * dx_ViewCoords.x + "
+ "dx_ViewCoords.z;\n"
+ << " gl_FragCoord.y = (input.gl_FragCoord.y * rhw) * dx_ViewCoords.y + "
+ "dx_ViewCoords.w;\n";
}
- pixelHLSL += " gl_FragCoord.z = (input.gl_FragCoord.z * rhw) * dx_DepthFront.x + dx_DepthFront.y;\n"
- " gl_FragCoord.w = rhw;\n";
+ if (programMetadata.usesViewScale())
+ {
+ // For Feature Level 9_3 and below, we need to correct gl_FragCoord.y to account
+ // for dx_ViewScale. On Feature Level 10_0+, gl_FragCoord.y is calculated above using
+ // dx_ViewCoords and is always correct irrespective of dx_ViewScale's value.
+ // NOTE: usesViewScale() can only be true on D3D11 (i.e. Shader Model 4.0+).
+ if (shaderModel >= 4 && mRenderer->getShaderModelSuffix() == "")
+ {
+ // Some assumptions:
+ // - dx_ViewScale.y = -1.0f when rendering to texture
+ // - dx_ViewScale.y = +1.0f when rendering to the default framebuffer
+ // - gl_FragCoord.y has been set correctly above.
+ //
+ // When rendering to the backbuffer, the code inverts gl_FragCoord's y coordinate.
+ // This involves subtracting the y coordinate from the height of the area being
+ // rendered to.
+ //
+ // First we calculate the height of the area being rendered to:
+ // render_area_height = (2.0f / (1.0f - input.gl_FragCoord.y * rhw)) *
+ // gl_FragCoord.y
+ //
+ // Note that when we're rendering to default FB, we want our output to be
+ // equivalent to:
+ // "gl_FragCoord.y = render_area_height - gl_FragCoord.y"
+ //
+ // When we're rendering to a texture, we want our output to be equivalent to:
+ // "gl_FragCoord.y = gl_FragCoord.y;"
+ //
+ // If we set scale_factor = ((1.0f + dx_ViewScale.y) / 2.0f), then notice that
+ // - When rendering to default FB: scale_factor = 1.0f
+ // - When rendering to texture: scale_factor = 0.0f
+ //
+ // Therefore, we can get our desired output by setting:
+ // "gl_FragCoord.y = scale_factor * render_area_height - dx_ViewScale.y *
+ // gl_FragCoord.y"
+ //
+ // Simplifying, this becomes:
+ pixelStream
+ << " gl_FragCoord.y = (1.0f + dx_ViewScale.y) * gl_FragCoord.y /"
+ "(1.0f - input.gl_FragCoord.y * rhw) - dx_ViewScale.y * gl_FragCoord.y;\n";
+ }
+ }
+
+ pixelStream << " gl_FragCoord.z = (input.gl_FragCoord.z * rhw) * dx_DepthFront.x + "
+ "dx_DepthFront.y;\n"
+ << " gl_FragCoord.w = rhw;\n";
}
- if (usesPointCoord && shaderModel >= 3)
+ if (pixelBuiltins.glPointCoord.enabled && shaderModel >= 3)
{
- pixelHLSL += " gl_PointCoord.x = input.gl_PointCoord.x;\n";
- pixelHLSL += " gl_PointCoord.y = 1.0 - input.gl_PointCoord.y;\n";
+ pixelStream << " gl_PointCoord.x = input.gl_PointCoord.x;\n"
+ << " gl_PointCoord.y = 1.0 - input.gl_PointCoord.y;\n";
}
- if (fragmentShader->mUsesFrontFacing)
+ if (fragmentShader->usesFrontFacing())
{
if (shaderModel <= 3)
{
- pixelHLSL += " gl_FrontFacing = (vFace * dx_DepthFront.z >= 0.0);\n";
+ pixelStream << " gl_FrontFacing = (vFace * dx_DepthFront.z >= 0.0);\n";
}
else
{
- pixelHLSL += " gl_FrontFacing = isFrontFace;\n";
+ pixelStream << " gl_FrontFacing = isFrontFace;\n";
}
}
- const std::vector<PackedVarying> &fragmentVaryings = fragmentShader->getVaryings();
- for (unsigned int varyingIndex = 0; varyingIndex < fragmentVaryings.size(); varyingIndex++)
+ for (const PackedVaryingRegister &registerInfo : varyingPacking.getRegisterList())
{
- const PackedVarying &varying = fragmentVaryings[varyingIndex];
- if (varying.registerAssigned())
+ const auto &packedVarying = *registerInfo.packedVarying;
+ const auto &varying = *packedVarying.varying;
+ ASSERT(!varying.isBuiltIn() && !varying.isStruct());
+
+ // Don't reference VS-only transform feedback varyings in the PS.
+ if (registerInfo.packedVarying->vertexOnly)
+ continue;
+
+ pixelStream << " ";
+
+ if (packedVarying.isStructField())
{
- ASSERT(!varying.isBuiltIn());
- for (unsigned int elementIndex = 0; elementIndex < varying.elementCount(); elementIndex++)
- {
- GLenum transposedType = TransposeMatrixType(varying.type);
- int variableRows = (varying.isStruct() ? 1 : VariableRowCount(transposedType));
- for (int row = 0; row < variableRows; row++)
- {
- std::string n = Str(varying.registerIndex + varying.columnIndex * data.caps->maxVaryingVectors + elementIndex * variableRows + row);
- pixelHLSL += " _" + varying.name;
-
- if (varying.isArray())
- {
- pixelHLSL += ArrayString(elementIndex);
- }
-
- if (variableRows > 1)
- {
- pixelHLSL += ArrayString(row);
- }
-
- if (varying.isStruct())
- {
- pixelHLSL += " = input.v" + n + ";\n"; break;
- }
- else
- {
- switch (VariableColumnCount(transposedType))
- {
- case 1: pixelHLSL += " = input.v" + n + ".x;\n"; break;
- case 2: pixelHLSL += " = input.v" + n + ".xy;\n"; break;
- case 3: pixelHLSL += " = input.v" + n + ".xyz;\n"; break;
- case 4: pixelHLSL += " = input.v" + n + ";\n"; break;
- default: UNREACHABLE();
- }
- }
- }
- }
+ pixelStream << decorateVariable(packedVarying.parentStructName) << ".";
}
- else
+
+ pixelStream << decorateVariable(varying.name);
+
+ if (varying.isArray())
+ {
+ WriteArrayString(pixelStream, registerInfo.varyingArrayIndex);
+ }
+
+ GLenum transposedType = TransposeMatrixType(varying.type);
+ if (VariableRowCount(transposedType) > 1)
{
- ASSERT(varying.isBuiltIn() || !varying.staticUse);
+ WriteArrayString(pixelStream, registerInfo.varyingRowIndex);
}
+
+ pixelStream << " = input.v" << registerInfo.semanticIndex;
+
+ switch (VariableColumnCount(transposedType))
+ {
+ case 1:
+ pixelStream << ".x";
+ break;
+ case 2:
+ pixelStream << ".xy";
+ break;
+ case 3:
+ pixelStream << ".xyz";
+ break;
+ case 4:
+ break;
+ default:
+ UNREACHABLE();
+ }
+ pixelStream << ";\n";
}
if (fragmentShader->usesDeferredInit())
{
- pixelHLSL += "\n"
- " initializeDeferredGlobals();\n";
+ pixelStream << "\n"
+ << " initializeDeferredGlobals();\n";
}
- pixelHLSL += "\n"
- " gl_main();\n"
- "\n"
- " return generateOutput();\n"
- "}\n";
+ pixelStream << "\n"
+ << " gl_main();\n"
+ << "\n"
+ << " return generateOutput();\n"
+ << "}\n";
+
+ *vertexHLSL = vertexStream.str();
+ *pixelHLSL = pixelStream.str();
return true;
}
-void DynamicHLSL::defineOutputVariables(ShaderD3D *fragmentShader, std::map<int, VariableLocation> *programOutputVars) const
+std::string DynamicHLSL::generateGeometryShaderPreamble(const VaryingPacking &varyingPacking) const
{
- const std::vector<sh::Attribute> &shaderOutputVars = fragmentShader->getActiveOutputVariables();
+ ASSERT(mRenderer->getMajorShaderModel() >= 4);
- for (unsigned int outputVariableIndex = 0; outputVariableIndex < shaderOutputVars.size(); outputVariableIndex++)
- {
- const sh::Attribute &outputVariable = shaderOutputVars[outputVariableIndex];
- const int baseLocation = outputVariable.location == -1 ? 0 : outputVariable.location;
+ std::stringstream preambleStream;
- ASSERT(outputVariable.staticUse);
+ const auto &builtins = varyingPacking.builtins(SHADER_VERTEX);
- if (outputVariable.arraySize > 0)
- {
- for (unsigned int elementIndex = 0; elementIndex < outputVariable.arraySize; elementIndex++)
- {
- const int location = baseLocation + elementIndex;
- ASSERT(programOutputVars->count(location) == 0);
- (*programOutputVars)[location] = VariableLocation(outputVariable.name, elementIndex, outputVariableIndex);
- }
- }
- else
+ preambleStream << "struct GS_INPUT\n";
+ generateVaryingLinkHLSL(SHADER_VERTEX, varyingPacking, preambleStream);
+ preambleStream << "\n"
+ << "struct GS_OUTPUT\n";
+ generateVaryingLinkHLSL(SHADER_GEOMETRY, varyingPacking, preambleStream);
+ preambleStream
+ << "\n"
+ << "void copyVertex(inout GS_OUTPUT output, GS_INPUT input, GS_INPUT flatinput)\n"
+ << "{\n"
+ << " output.gl_Position = input.gl_Position;\n";
+
+ if (builtins.glPointSize.enabled)
+ {
+ preambleStream << " output.gl_PointSize = input.gl_PointSize;\n";
+ }
+
+ for (const PackedVaryingRegister &varyingRegister : varyingPacking.getRegisterList())
+ {
+ preambleStream << " output.v" << varyingRegister.semanticIndex << " = ";
+ if (varyingRegister.packedVarying->interpolation == sh::INTERPOLATION_FLAT)
{
- ASSERT(programOutputVars->count(baseLocation) == 0);
- (*programOutputVars)[baseLocation] = VariableLocation(outputVariable.name, GL_INVALID_INDEX, outputVariableIndex);
+ preambleStream << "flat";
}
+ preambleStream << "input.v" << varyingRegister.semanticIndex << "; \n";
}
-}
-std::string DynamicHLSL::generateGeometryShaderHLSL(int registers, ShaderD3D *fragmentShader, ShaderD3D *vertexShader) const
-{
- // for now we only handle point sprite emulation
- ASSERT(vertexShader->mUsesPointSize && mRenderer->getMajorShaderModel() >= 4);
- return generatePointSpriteHLSL(registers, fragmentShader, vertexShader);
+ if (builtins.glFragCoord.enabled)
+ {
+ preambleStream << " output.gl_FragCoord = input.gl_FragCoord;\n";
+ }
+
+ // Only write the dx_Position if we aren't using point sprites
+ preambleStream << "#ifndef ANGLE_POINT_SPRITE_SHADER\n"
+ << " output.dx_Position = input.dx_Position;\n"
+ << "#endif // ANGLE_POINT_SPRITE_SHADER\n"
+ << "}\n";
+
+ return preambleStream.str();
}
-std::string DynamicHLSL::generatePointSpriteHLSL(int registers, ShaderD3D *fragmentShader, ShaderD3D *vertexShader) const
+std::string DynamicHLSL::generateGeometryShaderHLSL(gl::PrimitiveType primitiveType,
+ const gl::Data &data,
+ const gl::Program::Data &programData,
+ const bool useViewScale,
+ const std::string &preambleString) const
{
- ASSERT(registers >= 0);
- ASSERT(vertexShader->mUsesPointSize);
ASSERT(mRenderer->getMajorShaderModel() >= 4);
- std::string geomHLSL;
-
- const SemanticInfo &inSemantics = getSemanticInfo(registers, true, fragmentShader->mUsesFragCoord,
- false, true, false);
- const SemanticInfo &outSemantics = getSemanticInfo(registers, true, fragmentShader->mUsesFragCoord,
- fragmentShader->mUsesPointCoord, true, false);
-
- std::string varyingHLSL = generateVaryingHLSL(vertexShader);
- std::string inLinkHLSL = generateVaryingLinkHLSL(inSemantics, varyingHLSL);
- std::string outLinkHLSL = generateVaryingLinkHLSL(outSemantics, varyingHLSL);
-
- // TODO(geofflang): use context's caps
- geomHLSL += "uniform float4 dx_ViewCoords : register(c1);\n"
- "\n"
- "struct GS_INPUT\n" + inLinkHLSL + "\n" +
- "struct GS_OUTPUT\n" + outLinkHLSL + "\n" +
- "\n"
- "static float2 pointSpriteCorners[] = \n"
- "{\n"
- " float2( 0.5f, -0.5f),\n"
- " float2( 0.5f, 0.5f),\n"
- " float2(-0.5f, -0.5f),\n"
- " float2(-0.5f, 0.5f)\n"
- "};\n"
- "\n"
- "static float2 pointSpriteTexcoords[] = \n"
- "{\n"
- " float2(1.0f, 1.0f),\n"
- " float2(1.0f, 0.0f),\n"
- " float2(0.0f, 1.0f),\n"
- " float2(0.0f, 0.0f)\n"
- "};\n"
- "\n"
- "static float minPointSize = " + Str(mRenderer->getRendererCaps().minAliasedPointSize) + ".0f;\n"
- "static float maxPointSize = " + Str(mRenderer->getRendererCaps().maxAliasedPointSize) + ".0f;\n"
- "\n"
- "[maxvertexcount(4)]\n"
- "void main(point GS_INPUT input[1], inout TriangleStream<GS_OUTPUT> outStream)\n"
- "{\n"
- " GS_OUTPUT output = (GS_OUTPUT)0;\n"
- " output.gl_Position = input[0].gl_Position;\n"
- " output.gl_PointSize = input[0].gl_PointSize;\n";
-
- for (int r = 0; r < registers; r++)
+ std::stringstream shaderStream;
+
+ const bool pointSprites = (primitiveType == PRIMITIVE_POINTS);
+ const bool usesPointCoord = preambleString.find("gl_PointCoord") != std::string::npos;
+
+ const char *inputPT = nullptr;
+ const char *outputPT = nullptr;
+ int inputSize = 0;
+ int maxVertexOutput = 0;
+
+ switch (primitiveType)
{
- geomHLSL += " output.v" + Str(r) + " = input[0].v" + Str(r) + ";\n";
+ case PRIMITIVE_POINTS:
+ inputPT = "point";
+ outputPT = "Triangle";
+ inputSize = 1;
+ maxVertexOutput = 4;
+ break;
+
+ case PRIMITIVE_LINES:
+ case PRIMITIVE_LINE_STRIP:
+ case PRIMITIVE_LINE_LOOP:
+ inputPT = "line";
+ outputPT = "Line";
+ inputSize = 2;
+ maxVertexOutput = 2;
+ break;
+
+ case PRIMITIVE_TRIANGLES:
+ case PRIMITIVE_TRIANGLE_STRIP:
+ case PRIMITIVE_TRIANGLE_FAN:
+ inputPT = "triangle";
+ outputPT = "Triangle";
+ inputSize = 3;
+ maxVertexOutput = 3;
+ break;
+
+ default:
+ UNREACHABLE();
+ break;
}
- if (fragmentShader->mUsesFragCoord)
+ if (pointSprites)
{
- geomHLSL += " output.gl_FragCoord = input[0].gl_FragCoord;\n";
+ shaderStream << "#define ANGLE_POINT_SPRITE_SHADER\n"
+ "\n"
+ "uniform float4 dx_ViewCoords : register(c1);\n";
+
+ if (useViewScale)
+ {
+ shaderStream << "uniform float2 dx_ViewScale : register(c3);\n";
+ }
+
+ shaderStream << "\n"
+ "static float2 pointSpriteCorners[] = \n"
+ "{\n"
+ " float2( 0.5f, -0.5f),\n"
+ " float2( 0.5f, 0.5f),\n"
+ " float2(-0.5f, -0.5f),\n"
+ " float2(-0.5f, 0.5f)\n"
+ "};\n"
+ "\n"
+ "static float2 pointSpriteTexcoords[] = \n"
+ "{\n"
+ " float2(1.0f, 1.0f),\n"
+ " float2(1.0f, 0.0f),\n"
+ " float2(0.0f, 1.0f),\n"
+ " float2(0.0f, 0.0f)\n"
+ "};\n"
+ "\n"
+ "static float minPointSize = "
+ << static_cast<int>(data.caps->minAliasedPointSize)
+ << ".0f;\n"
+ "static float maxPointSize = "
+ << static_cast<int>(data.caps->maxAliasedPointSize) << ".0f;\n"
+ << "\n";
}
- geomHLSL += " \n"
- " float gl_PointSize = clamp(input[0].gl_PointSize, minPointSize, maxPointSize);\n"
- " float4 dx_Position = input[0].dx_Position;\n"
- " float2 viewportScale = float2(1.0f / dx_ViewCoords.x, 1.0f / dx_ViewCoords.y) * dx_Position.w;\n";
+ shaderStream << preambleString << "\n"
+ << "[maxvertexcount(" << maxVertexOutput << ")]\n"
+ << "void main(" << inputPT << " GS_INPUT input[" << inputSize << "], ";
- for (int corner = 0; corner < 4; corner++)
+ if (primitiveType == PRIMITIVE_TRIANGLE_STRIP)
{
- geomHLSL += " \n"
- " output.dx_Position = dx_Position + float4(pointSpriteCorners[" + Str(corner) + "] * viewportScale * gl_PointSize, 0.0f, 0.0f);\n";
+ shaderStream << "uint primitiveID : SV_PrimitiveID, ";
+ }
+
+ shaderStream << " inout " << outputPT << "Stream<GS_OUTPUT> outStream)\n"
+ << "{\n"
+ << " GS_OUTPUT output = (GS_OUTPUT)0;\n";
- if (fragmentShader->mUsesPointCoord)
+ if (primitiveType == PRIMITIVE_TRIANGLE_STRIP)
+ {
+ shaderStream << " uint lastVertexIndex = (primitiveID % 2 == 0 ? 2 : 1);\n";
+ }
+ else
+ {
+ shaderStream << " uint lastVertexIndex = " << (inputSize - 1) << ";\n";
+ }
+
+ for (int vertexIndex = 0; vertexIndex < inputSize; ++vertexIndex)
+ {
+ shaderStream << " copyVertex(output, input[" << vertexIndex
+ << "], input[lastVertexIndex]);\n";
+
+ if (!pointSprites)
{
- geomHLSL += " output.gl_PointCoord = pointSpriteTexcoords[" + Str(corner) + "];\n";
+ ASSERT(inputSize == maxVertexOutput);
+ shaderStream << " outStream.Append(output);\n";
}
+ }
+
+ if (pointSprites)
+ {
+ shaderStream << "\n"
+ " float4 dx_Position = input[0].dx_Position;\n"
+ " float gl_PointSize = clamp(input[0].gl_PointSize, minPointSize, "
+ "maxPointSize);\n"
+ " float2 viewportScale = float2(1.0f / dx_ViewCoords.x, 1.0f / "
+ "dx_ViewCoords.y) * dx_Position.w;\n";
+
+ for (int corner = 0; corner < 4; corner++)
+ {
+ if (useViewScale)
+ {
+ shaderStream << " \n"
+ " output.dx_Position = dx_Position + float4(1.0f, "
+ "-dx_ViewScale.y, 1.0f, 1.0f)"
+ " * float4(pointSpriteCorners["
+ << corner << "] * viewportScale * gl_PointSize, 0.0f, 0.0f);\n";
+ }
+ else
+ {
+ shaderStream << "\n"
+ " output.dx_Position = dx_Position + float4(pointSpriteCorners["
+ << corner << "] * viewportScale * gl_PointSize, 0.0f, 0.0f);\n";
+ }
- geomHLSL += " outStream.Append(output);\n";
+ if (usesPointCoord)
+ {
+ shaderStream << " output.gl_PointCoord = pointSpriteTexcoords[" << corner
+ << "];\n";
+ }
+
+ shaderStream << " outStream.Append(output);\n";
+ }
}
- geomHLSL += " \n"
- " outStream.RestartStrip();\n"
- "}\n";
+ shaderStream << " \n"
+ " outStream.RestartStrip();\n"
+ "}\n";
- return geomHLSL;
+ return shaderStream.str();
}
// This method needs to match OutputHLSL::decorate
@@ -1217,9 +1006,12 @@ std::string DynamicHLSL::decorateVariable(const std::string &name)
return name;
}
-std::string DynamicHLSL::generateAttributeConversionHLSL(const VertexFormat &vertexFormat, const sh::ShaderVariable &shaderAttrib) const
+std::string DynamicHLSL::generateAttributeConversionHLSL(
+ gl::VertexFormatType vertexFormatType,
+ const sh::ShaderVariable &shaderAttrib) const
{
- std::string attribString = "input." + decorateVariable(shaderAttrib.name);
+ const gl::VertexFormat &vertexFormat = gl::GetVertexFormatFromType(vertexFormatType);
+ std::string attribString = "input." + decorateVariable(shaderAttrib.name);
// Matrix
if (IsMatrixType(shaderAttrib.type))
@@ -1228,15 +1020,16 @@ std::string DynamicHLSL::generateAttributeConversionHLSL(const VertexFormat &ver
}
GLenum shaderComponentType = VariableComponentType(shaderAttrib.type);
- int shaderComponentCount = VariableComponentCount(shaderAttrib.type);
+ int shaderComponentCount = VariableComponentCount(shaderAttrib.type);
// Perform integer to float conversion (if necessary)
- bool requiresTypeConversion = (shaderComponentType == GL_FLOAT && vertexFormat.mType != GL_FLOAT);
+ bool requiresTypeConversion =
+ (shaderComponentType == GL_FLOAT && vertexFormat.type != GL_FLOAT);
if (requiresTypeConversion)
{
// TODO: normalization for 32-bit integer formats
- ASSERT(!vertexFormat.mNormalized && !vertexFormat.mPureInteger);
+ ASSERT(!vertexFormat.normalized && !vertexFormat.pureInteger);
return "float" + Str(shaderComponentCount) + "(" + attribString + ")";
}
@@ -1244,22 +1037,57 @@ std::string DynamicHLSL::generateAttributeConversionHLSL(const VertexFormat &ver
return attribString;
}
-void DynamicHLSL::getInputLayoutSignature(const VertexFormat inputLayout[], GLenum signature[]) const
+void DynamicHLSL::getPixelShaderOutputKey(const gl::Data &data,
+ const gl::Program::Data &programData,
+ const ProgramD3DMetadata &metadata,
+ std::vector<PixelShaderOutputVariable> *outPixelShaderKey)
{
- for (size_t inputIndex = 0; inputIndex < MAX_VERTEX_ATTRIBS; inputIndex++)
- {
- const VertexFormat &vertexFormat = inputLayout[inputIndex];
+ // Two cases when writing to gl_FragColor and using ESSL 1.0:
+ // - with a 3.0 context, the output color is copied to channel 0
+ // - with a 2.0 context, the output color is broadcast to all channels
+ bool broadcast = metadata.usesBroadcast(data);
+ const unsigned int numRenderTargets =
+ (broadcast || metadata.usesMultipleFragmentOuts() ? data.caps->maxDrawBuffers : 1);
- if (vertexFormat.mType == GL_NONE)
+ if (metadata.getMajorShaderVersion() < 300)
+ {
+ for (unsigned int renderTargetIndex = 0; renderTargetIndex < numRenderTargets;
+ renderTargetIndex++)
{
- signature[inputIndex] = GL_NONE;
+ PixelShaderOutputVariable outputKeyVariable;
+ outputKeyVariable.type = GL_FLOAT_VEC4;
+ outputKeyVariable.name = "gl_Color" + Str(renderTargetIndex);
+ outputKeyVariable.source =
+ broadcast ? "gl_Color[0]" : "gl_Color[" + Str(renderTargetIndex) + "]";
+ outputKeyVariable.outputIndex = renderTargetIndex;
+
+ outPixelShaderKey->push_back(outputKeyVariable);
}
- else
+ }
+ else
+ {
+ const auto &shaderOutputVars =
+ metadata.getFragmentShader()->getData().getActiveOutputVariables();
+
+ for (auto outputPair : programData.getOutputVariables())
{
- bool gpuConverted = ((mRenderer->getVertexConversionType(vertexFormat) & VERTEX_CONVERT_GPU) != 0);
- signature[inputIndex] = (gpuConverted ? GL_TRUE : GL_FALSE);
+ const VariableLocation &outputLocation = outputPair.second;
+ const sh::ShaderVariable &outputVariable = shaderOutputVars[outputLocation.index];
+ const std::string &variableName = "out_" + outputLocation.name;
+ const std::string &elementString =
+ (outputLocation.element == GL_INVALID_INDEX ? "" : Str(outputLocation.element));
+
+ ASSERT(outputVariable.staticUse);
+
+ PixelShaderOutputVariable outputKeyVariable;
+ outputKeyVariable.type = outputVariable.type;
+ outputKeyVariable.name = variableName + elementString;
+ outputKeyVariable.source = variableName + ArrayString(outputLocation.element);
+ outputKeyVariable.outputIndex = outputPair.first;
+
+ outPixelShaderKey->push_back(outputKeyVariable);
}
}
}
-}
+} // namespace rx
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/DynamicHLSL.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/DynamicHLSL.h
index 26ae13b342..69d941c06a 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/DynamicHLSL.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/DynamicHLSL.h
@@ -9,13 +9,15 @@
#ifndef LIBANGLE_RENDERER_D3D_DYNAMICHLSL_H_
#define LIBANGLE_RENDERER_D3D_DYNAMICHLSL_H_
-#include "common/angleutils.h"
-#include "libANGLE/Constants.h"
+#include <map>
+#include <vector>
#include "angle_gl.h"
-
-#include <vector>
-#include <map>
+#include "common/angleutils.h"
+#include "libANGLE/Constants.h"
+#include "libANGLE/Program.h"
+#include "libANGLE/formatutils.h"
+#include "libANGLE/renderer/d3d/RendererD3D.h"
namespace sh
{
@@ -27,19 +29,16 @@ namespace gl
{
class InfoLog;
struct VariableLocation;
-struct LinkedVarying;
struct VertexAttribute;
-struct VertexFormat;
-struct PackedVarying;
struct Data;
}
namespace rx
{
-class RendererD3D;
+struct PackedVarying;
+class ProgramD3DMetadata;
class ShaderD3D;
-
-typedef const gl::PackedVarying *VaryingPacking[gl::IMPLEMENTATION_MAX_VARYING_VECTORS][4];
+class VaryingPacking;
struct PixelShaderOutputVariable
{
@@ -54,46 +53,52 @@ class DynamicHLSL : angle::NonCopyable
public:
explicit DynamicHLSL(RendererD3D *const renderer);
- int packVaryings(gl::InfoLog &infoLog, VaryingPacking packing, ShaderD3D *fragmentShader,
- ShaderD3D *vertexShader, const std::vector<std::string>& transformFeedbackVaryings);
- std::string generateVertexShaderForInputLayout(const std::string &sourceShader, const gl::VertexFormat inputLayout[],
- const sh::Attribute shaderAttributes[]) const;
- std::string generatePixelShaderForOutputSignature(const std::string &sourceShader, const std::vector<PixelShaderOutputVariable> &outputVariables,
- bool usesFragDepth, const std::vector<GLenum> &outputLayout) const;
- bool generateShaderLinkHLSL(const gl::Data &data, gl::InfoLog &infoLog, int registers,
- const VaryingPacking packing,
- std::string &pixelHLSL, std::string &vertexHLSL,
- ShaderD3D *fragmentShader, ShaderD3D *vertexShader,
- const std::vector<std::string> &transformFeedbackVaryings,
- std::vector<gl::LinkedVarying> *linkedVaryings,
- std::map<int, gl::VariableLocation> *programOutputVars,
- std::vector<PixelShaderOutputVariable> *outPixelShaderKey,
- bool *outUsesFragDepth) const;
-
- std::string generateGeometryShaderHLSL(int registers, ShaderD3D *fragmentShader, ShaderD3D *vertexShader) const;
- void getInputLayoutSignature(const gl::VertexFormat inputLayout[], GLenum signature[]) const;
+ std::string generateVertexShaderForInputLayout(
+ const std::string &sourceShader,
+ const gl::InputLayout &inputLayout,
+ const std::vector<sh::Attribute> &shaderAttributes) const;
+ std::string generatePixelShaderForOutputSignature(
+ const std::string &sourceShader,
+ const std::vector<PixelShaderOutputVariable> &outputVariables,
+ bool usesFragDepth,
+ const std::vector<GLenum> &outputLayout) const;
+ bool generateShaderLinkHLSL(const gl::Data &data,
+ const gl::Program::Data &programData,
+ const ProgramD3DMetadata &programMetadata,
+ const VaryingPacking &varyingPacking,
+ std::string *pixelHLSL,
+ std::string *vertexHLSL) const;
+
+ std::string generateGeometryShaderPreamble(const VaryingPacking &varyingPacking) const;
+
+ std::string generateGeometryShaderHLSL(gl::PrimitiveType primitiveType,
+ const gl::Data &data,
+ const gl::Program::Data &programData,
+ const bool useViewScale,
+ const std::string &preambleString) const;
+
+ void getPixelShaderOutputKey(const gl::Data &data,
+ const gl::Program::Data &programData,
+ const ProgramD3DMetadata &metadata,
+ std::vector<PixelShaderOutputVariable> *outPixelShaderKey);
private:
RendererD3D *const mRenderer;
- struct SemanticInfo;
-
- std::string getVaryingSemantic(bool pointSize) const;
- SemanticInfo getSemanticInfo(int startRegisters, bool position, bool fragCoord, bool pointCoord,
- bool pointSize, bool pixelShader) const;
- std::string generateVaryingLinkHLSL(const SemanticInfo &info, const std::string &varyingHLSL) const;
- std::string generateVaryingHLSL(const ShaderD3D *shader) const;
- void storeUserLinkedVaryings(const ShaderD3D *vertexShader, std::vector<gl::LinkedVarying> *linkedVaryings) const;
- void storeBuiltinLinkedVaryings(const SemanticInfo &info, std::vector<gl::LinkedVarying> *linkedVaryings) const;
- void defineOutputVariables(ShaderD3D *fragmentShader, std::map<int, gl::VariableLocation> *programOutputVars) const;
- std::string generatePointSpriteHLSL(int registers, ShaderD3D *fragmentShader, ShaderD3D *vertexShader) const;
+ void generateVaryingLinkHLSL(ShaderType shaderType,
+ const VaryingPacking &varyingPacking,
+ std::stringstream &linkStream) const;
+ void generateVaryingHLSL(const VaryingPacking &varyingPacking,
+ std::stringstream &hlslStream) const;
// Prepend an underscore
static std::string decorateVariable(const std::string &name);
- std::string generateAttributeConversionHLSL(const gl::VertexFormat &vertexFormat, const sh::ShaderVariable &shaderAttrib) const;
+ std::string generateAttributeConversionHLSL(gl::VertexFormatType vertexFormatType,
+ const sh::ShaderVariable &shaderAttrib) const;
};
+std::string GetVaryingSemantic(int majorShaderModel, bool programUsesPointSize);
}
-#endif // LIBANGLE_RENDERER_D3D_DYNAMICHLSL_H_
+#endif // LIBANGLE_RENDERER_D3D_DYNAMICHLSL_H_
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/EGLImageD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/EGLImageD3D.cpp
new file mode 100644
index 0000000000..ca4b16987f
--- /dev/null
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/EGLImageD3D.cpp
@@ -0,0 +1,132 @@
+//
+// 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.
+//
+
+// EGLImageD3D.cpp: Implements the rx::EGLImageD3D class, the D3D implementation of EGL images
+
+#include "libANGLE/renderer/d3d/EGLImageD3D.h"
+
+#include "common/debug.h"
+#include "common/utilities.h"
+#include "libANGLE/AttributeMap.h"
+#include "libANGLE/Texture.h"
+#include "libANGLE/renderer/d3d/RenderbufferD3D.h"
+#include "libANGLE/renderer/d3d/RendererD3D.h"
+#include "libANGLE/renderer/d3d/RenderTargetD3D.h"
+#include "libANGLE/renderer/d3d/TextureD3D.h"
+#include "libANGLE/renderer/d3d/TextureStorage.h"
+
+#include <EGL/eglext.h>
+
+namespace rx
+{
+static gl::ImageIndex GetImageIndex(GLenum target, size_t mip, size_t layer)
+{
+ if (target == GL_TEXTURE_3D)
+ {
+ return gl::ImageIndex::Make3D(static_cast<GLint>(mip), static_cast<GLint>(layer));
+ }
+ else
+ {
+ ASSERT(layer == 0);
+ return gl::ImageIndex::MakeGeneric(target, static_cast<GLint>(mip));
+ }
+}
+
+EGLImageD3D::EGLImageD3D(RendererD3D *renderer,
+ EGLenum target,
+ egl::ImageSibling *buffer,
+ const egl::AttributeMap &attribs)
+ : mRenderer(renderer), mBuffer(buffer), mAttachmentBuffer(nullptr), mRenderTarget(nullptr)
+{
+ ASSERT(renderer != nullptr);
+ ASSERT(buffer != nullptr);
+
+ if (egl::IsTextureTarget(target))
+ {
+ mAttachmentBuffer = GetImplAs<TextureD3D>(GetAs<gl::Texture>(buffer));
+ mAttachmentTarget = gl::FramebufferAttachment::Target(
+ GL_NONE, GetImageIndex(egl_gl::EGLImageTargetToGLTextureTarget(target),
+ attribs.get(EGL_GL_TEXTURE_LEVEL_KHR, 0),
+ attribs.get(EGL_GL_TEXTURE_ZOFFSET_KHR, 0)));
+ }
+ else if (egl::IsRenderbufferTarget(target))
+ {
+ mAttachmentBuffer = GetImplAs<RenderbufferD3D>(GetAs<gl::Renderbuffer>(buffer));
+ mAttachmentTarget =
+ gl::FramebufferAttachment::Target(GL_NONE, gl::ImageIndex::MakeInvalid());
+ }
+ else
+ {
+ UNREACHABLE();
+ }
+}
+
+EGLImageD3D::~EGLImageD3D()
+{
+ SafeDelete(mRenderTarget);
+}
+
+egl::Error EGLImageD3D::initialize()
+{
+ return egl::Error(EGL_SUCCESS);
+}
+
+gl::Error EGLImageD3D::orphan(egl::ImageSibling *sibling)
+{
+ if (sibling == mBuffer)
+ {
+ gl::Error error = copyToLocalRendertarget();
+ if (error.isError())
+ {
+ return error;
+ }
+ }
+
+ return gl::Error(GL_NO_ERROR);
+}
+
+gl::Error EGLImageD3D::getRenderTarget(RenderTargetD3D **outRT) const
+{
+ if (mAttachmentBuffer)
+ {
+ FramebufferAttachmentRenderTarget *rt = nullptr;
+ gl::Error error = mAttachmentBuffer->getAttachmentRenderTarget(mAttachmentTarget, &rt);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ *outRT = static_cast<RenderTargetD3D *>(rt);
+ return gl::Error(GL_NO_ERROR);
+ }
+ else
+ {
+ ASSERT(mRenderTarget);
+ *outRT = mRenderTarget;
+ return gl::Error(GL_NO_ERROR);
+ }
+}
+
+gl::Error EGLImageD3D::copyToLocalRendertarget()
+{
+ ASSERT(mBuffer != nullptr);
+ ASSERT(mAttachmentBuffer != nullptr);
+ ASSERT(mRenderTarget == nullptr);
+
+ RenderTargetD3D *curRenderTarget = nullptr;
+ gl::Error error = getRenderTarget(&curRenderTarget);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ // Clear the source image buffers
+ mBuffer = nullptr;
+ mAttachmentBuffer = nullptr;
+
+ return mRenderer->createRenderTargetCopy(curRenderTarget, &mRenderTarget);
+}
+}
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/EGLImageD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/EGLImageD3D.h
new file mode 100644
index 0000000000..6ec33e08f2
--- /dev/null
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/EGLImageD3D.h
@@ -0,0 +1,56 @@
+//
+// 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.
+//
+
+// EGLImageD3D.h: Defines the rx::EGLImageD3D class, the D3D implementation of EGL images
+
+#ifndef LIBANGLE_RENDERER_D3D_EGLIMAGED3D_H_
+#define LIBANGLE_RENDERER_D3D_EGLIMAGED3D_H_
+
+#include "libANGLE/FramebufferAttachment.h"
+#include "libANGLE/renderer/ImageImpl.h"
+
+namespace egl
+{
+class AttributeMap;
+}
+
+namespace rx
+{
+class TextureD3D;
+class RenderbufferD3D;
+class RendererD3D;
+class RenderTargetD3D;
+
+class EGLImageD3D final : public ImageImpl
+{
+ public:
+ EGLImageD3D(RendererD3D *renderer,
+ EGLenum target,
+ egl::ImageSibling *buffer,
+ const egl::AttributeMap &attribs);
+ ~EGLImageD3D() override;
+
+ egl::Error initialize() override;
+
+ gl::Error orphan(egl::ImageSibling *sibling) override;
+
+ gl::Error getRenderTarget(RenderTargetD3D **outRT) const;
+
+ private:
+ gl::Error copyToLocalRendertarget();
+
+ RendererD3D *mRenderer;
+
+ egl::ImageSibling *mBuffer;
+
+ gl::FramebufferAttachment::Target mAttachmentTarget;
+ FramebufferAttachmentObjectImpl *mAttachmentBuffer;
+
+ RenderTargetD3D *mRenderTarget;
+};
+}
+
+#endif // LIBANGLE_RENDERER_D3D_EGLIMAGED3D_H_
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/FramebufferD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/FramebufferD3D.cpp
index 1a4734b269..82967aced0 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/FramebufferD3D.cpp
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/FramebufferD3D.cpp
@@ -8,6 +8,7 @@
#include "libANGLE/renderer/d3d/FramebufferD3D.h"
+#include "common/BitSetIterator.h"
#include "libANGLE/formatutils.h"
#include "libANGLE/Framebuffer.h"
#include "libANGLE/FramebufferAttachment.h"
@@ -53,7 +54,7 @@ ClearParameters GetClearParameters(const gl::State &state, GLbitfield mask)
const gl::Framebuffer *framebufferObject = state.getDrawFramebuffer();
if (mask & GL_COLOR_BUFFER_BIT)
{
- if (framebufferObject->hasEnabledColorAttachment())
+ if (framebufferObject->hasEnabledDrawBuffer())
{
for (unsigned int i = 0; i < ArraySize(clearParams.clearColor); i++)
{
@@ -85,67 +86,28 @@ ClearParameters GetClearParameters(const gl::State &state, GLbitfield mask)
}
FramebufferD3D::FramebufferD3D(const gl::Framebuffer::Data &data, RendererD3D *renderer)
- : FramebufferImpl(data),
- mRenderer(renderer),
- mColorAttachmentsForRender(mData.mColorAttachments.size(), nullptr),
- mInvalidateColorAttachmentCache(true)
+ : FramebufferImpl(data), mRenderer(renderer)
{
- ASSERT(mRenderer != nullptr);
}
FramebufferD3D::~FramebufferD3D()
{
}
-void FramebufferD3D::setColorAttachment(size_t, const gl::FramebufferAttachment *)
-{
- mInvalidateColorAttachmentCache = true;
-}
-
-void FramebufferD3D::setDepthAttachment(const gl::FramebufferAttachment *)
-{
-}
-
-void FramebufferD3D::setStencilAttachment(const gl::FramebufferAttachment *)
-{
-}
-
-void FramebufferD3D::setDepthStencilAttachment(const gl::FramebufferAttachment *)
-{
-}
-
-void FramebufferD3D::setDrawBuffers(size_t, const GLenum *)
-{
- mInvalidateColorAttachmentCache = true;
-}
-
-void FramebufferD3D::setReadBuffer(GLenum)
-{
-}
-
-gl::Error FramebufferD3D::invalidate(size_t, const GLenum *)
-{
- // No-op in D3D
- return gl::Error(GL_NO_ERROR);
-}
-
-gl::Error FramebufferD3D::invalidateSub(size_t, const GLenum *, const gl::Rectangle &)
-{
- // No-op in D3D
- return gl::Error(GL_NO_ERROR);
-}
-
gl::Error FramebufferD3D::clear(const gl::Data &data, GLbitfield mask)
{
const gl::State &state = *data.state;
ClearParameters clearParams = GetClearParameters(state, mask);
- return clear(state, clearParams);
+ return clear(data, clearParams);
}
-gl::Error FramebufferD3D::clearBufferfv(const gl::State &state, GLenum buffer, GLint drawbuffer, const GLfloat *values)
+gl::Error FramebufferD3D::clearBufferfv(const gl::Data &data,
+ GLenum buffer,
+ GLint drawbuffer,
+ const GLfloat *values)
{
// glClearBufferfv can be called to clear the color buffer or depth buffer
- ClearParameters clearParams = GetClearParameters(state, 0);
+ ClearParameters clearParams = GetClearParameters(*data.state, 0);
if (buffer == GL_COLOR)
{
@@ -163,13 +125,16 @@ gl::Error FramebufferD3D::clearBufferfv(const gl::State &state, GLenum buffer, G
clearParams.depthClearValue = values[0];
}
- return clear(state, clearParams);
+ return clear(data, clearParams);
}
-gl::Error FramebufferD3D::clearBufferuiv(const gl::State &state, GLenum buffer, GLint drawbuffer, const GLuint *values)
+gl::Error FramebufferD3D::clearBufferuiv(const gl::Data &data,
+ GLenum buffer,
+ GLint drawbuffer,
+ const GLuint *values)
{
// glClearBufferuiv can only be called to clear a color buffer
- ClearParameters clearParams = GetClearParameters(state, 0);
+ ClearParameters clearParams = GetClearParameters(*data.state, 0);
for (unsigned int i = 0; i < ArraySize(clearParams.clearColor); i++)
{
clearParams.clearColor[i] = (drawbuffer == static_cast<int>(i));
@@ -177,13 +142,16 @@ gl::Error FramebufferD3D::clearBufferuiv(const gl::State &state, GLenum buffer,
clearParams.colorUIClearValue = gl::ColorUI(values[0], values[1], values[2], values[3]);
clearParams.colorClearType = GL_UNSIGNED_INT;
- return clear(state, clearParams);
+ return clear(data, clearParams);
}
-gl::Error FramebufferD3D::clearBufferiv(const gl::State &state, GLenum buffer, GLint drawbuffer, const GLint *values)
+gl::Error FramebufferD3D::clearBufferiv(const gl::Data &data,
+ GLenum buffer,
+ GLint drawbuffer,
+ const GLint *values)
{
// glClearBufferiv can be called to clear the color buffer or stencil buffer
- ClearParameters clearParams = GetClearParameters(state, 0);
+ ClearParameters clearParams = GetClearParameters(*data.state, 0);
if (buffer == GL_COLOR)
{
@@ -201,19 +169,23 @@ gl::Error FramebufferD3D::clearBufferiv(const gl::State &state, GLenum buffer, G
clearParams.stencilClearValue = values[1];
}
- return clear(state, clearParams);
+ return clear(data, clearParams);
}
-gl::Error FramebufferD3D::clearBufferfi(const gl::State &state, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil)
+gl::Error FramebufferD3D::clearBufferfi(const gl::Data &data,
+ GLenum buffer,
+ GLint drawbuffer,
+ GLfloat depth,
+ GLint stencil)
{
// glClearBufferfi can only be called to clear a depth stencil buffer
- ClearParameters clearParams = GetClearParameters(state, 0);
+ ClearParameters clearParams = GetClearParameters(*data.state, 0);
clearParams.clearDepth = true;
clearParams.depthClearValue = depth;
clearParams.clearStencil = true;
clearParams.stencilClearValue = stencil;
- return clear(state, clearParams);
+ return clear(data, clearParams);
}
GLenum FramebufferD3D::getImplementationColorReadFormat() const
@@ -226,7 +198,7 @@ GLenum FramebufferD3D::getImplementationColorReadFormat() const
}
RenderTargetD3D *attachmentRenderTarget = NULL;
- gl::Error error = GetAttachmentRenderTarget(readAttachment, &attachmentRenderTarget);
+ gl::Error error = readAttachment->getRenderTarget(&attachmentRenderTarget);
if (error.isError())
{
return GL_NONE;
@@ -248,7 +220,7 @@ GLenum FramebufferD3D::getImplementationColorReadType() const
}
RenderTargetD3D *attachmentRenderTarget = NULL;
- gl::Error error = GetAttachmentRenderTarget(readAttachment, &attachmentRenderTarget);
+ gl::Error error = readAttachment->getRenderTarget(&attachmentRenderTarget);
if (error.isError())
{
return GL_NONE;
@@ -264,17 +236,15 @@ gl::Error FramebufferD3D::readPixels(const gl::State &state, const gl::Rectangle
{
const gl::PixelPackState &packState = state.getPackState();
- if (packState.rowLength != 0 || packState.skipRows != 0 || packState.skipPixels != 0)
- {
- UNIMPLEMENTED();
- return gl::Error(GL_INVALID_OPERATION, "invalid pixel store parameters in readPixels");
- }
-
GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, type);
const gl::InternalFormat &sizedFormatInfo = gl::GetInternalFormatInfo(sizedInternalFormat);
- GLuint outputPitch = sizedFormatInfo.computeRowPitch(type, area.width, packState.alignment, 0);
+ GLuint outputPitch =
+ sizedFormatInfo.computeRowPitch(type, area.width, packState.alignment, packState.rowLength);
+ GLsizei outputSkipBytes = sizedFormatInfo.computeSkipPixels(
+ outputPitch, 0, 0, packState.skipRows, packState.skipPixels);
- return readPixels(area, format, type, outputPitch, packState, reinterpret_cast<uint8_t*>(pixels));
+ return readPixelsImpl(area, format, type, outputPitch, packState,
+ reinterpret_cast<uint8_t *>(pixels) + outputSkipBytes);
}
gl::Error FramebufferD3D::blit(const gl::State &state, const gl::Rectangle &sourceArea, const gl::Rectangle &destArea,
@@ -291,7 +261,7 @@ gl::Error FramebufferD3D::blit(const gl::State &state, const gl::Rectangle &sour
bool blitStencil = false;
if ((mask & GL_STENCIL_BUFFER_BIT) &&
sourceFramebuffer->getStencilbuffer() != nullptr &&
- mData.mStencilAttachment != nullptr)
+ mData.getStencilAttachment() != nullptr)
{
blitStencil = true;
}
@@ -299,7 +269,7 @@ gl::Error FramebufferD3D::blit(const gl::State &state, const gl::Rectangle &sour
bool blitDepth = false;
if ((mask & GL_DEPTH_BUFFER_BIT) &&
sourceFramebuffer->getDepthbuffer() != nullptr &&
- mData.mDepthAttachment != nullptr)
+ mData.getDepthAttachment() != nullptr)
{
blitDepth = true;
}
@@ -318,146 +288,99 @@ gl::Error FramebufferD3D::blit(const gl::State &state, const gl::Rectangle &sour
return gl::Error(GL_NO_ERROR);
}
-GLenum FramebufferD3D::checkStatus() const
+bool FramebufferD3D::checkStatus() const
{
+ // if we have both a depth and stencil buffer, they must refer to the same object
+ // since we only support packed_depth_stencil and not separate depth and stencil
+ if (mData.getDepthAttachment() != nullptr && mData.getStencilAttachment() != nullptr &&
+ mData.getDepthStencilAttachment() == nullptr)
+ {
+ return false;
+ }
+
// D3D11 does not allow for overlapping RenderTargetViews, so ensure uniqueness
- for (size_t colorAttachment = 0; colorAttachment < mData.mColorAttachments.size(); colorAttachment++)
+ const auto &colorAttachments = mData.getColorAttachments();
+ for (size_t colorAttachment = 0; colorAttachment < colorAttachments.size(); colorAttachment++)
{
- const gl::FramebufferAttachment *attachment = mData.mColorAttachments[colorAttachment];
- if (attachment != nullptr)
+ const gl::FramebufferAttachment &attachment = colorAttachments[colorAttachment];
+ if (attachment.isAttached())
{
for (size_t prevColorAttachment = 0; prevColorAttachment < colorAttachment; prevColorAttachment++)
{
- const gl::FramebufferAttachment *prevAttachment = mData.mColorAttachments[prevColorAttachment];
- if (prevAttachment != nullptr &&
- (attachment->id() == prevAttachment->id() &&
- attachment->type() == prevAttachment->type()))
+ const gl::FramebufferAttachment &prevAttachment = colorAttachments[prevColorAttachment];
+ if (prevAttachment.isAttached() &&
+ (attachment.id() == prevAttachment.id() &&
+ attachment.type() == prevAttachment.type()))
{
- return GL_FRAMEBUFFER_UNSUPPORTED;
+ return false;
}
}
}
}
- return GL_FRAMEBUFFER_COMPLETE;
+ // D3D requires all render targets to have the same dimensions.
+ if (!mData.attachmentsHaveSameDimensions())
+ {
+ return false;
+ }
+
+ return true;
}
-const gl::AttachmentList &FramebufferD3D::getColorAttachmentsForRender(const Workarounds &workarounds) const
+void FramebufferD3D::syncState(const gl::Framebuffer::DirtyBits &dirtyBits)
{
- if (!workarounds.mrtPerfWorkaround)
- {
- return mData.mColorAttachments;
- }
+ bool invalidateColorAttachmentCache = false;
- if (!mInvalidateColorAttachmentCache)
+ if (!mColorAttachmentsForRender.valid())
{
- return mColorAttachmentsForRender;
+ invalidateColorAttachmentCache = true;
}
- // Does not actually free memory
- mColorAttachmentsForRender.clear();
-
- for (size_t attachmentIndex = 0; attachmentIndex < mData.mColorAttachments.size(); ++attachmentIndex)
+ for (auto dirtyBit : angle::IterateBitSet(dirtyBits))
{
- GLenum drawBufferState = mData.mDrawBufferStates[attachmentIndex];
- gl::FramebufferAttachment *colorAttachment = mData.mColorAttachments[attachmentIndex];
-
- if (colorAttachment != nullptr && drawBufferState != GL_NONE)
+ if ((dirtyBit >= gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0 &&
+ dirtyBit < gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_MAX) ||
+ dirtyBit == gl::Framebuffer::DIRTY_BIT_DRAW_BUFFERS)
{
- ASSERT(drawBufferState == GL_BACK || drawBufferState == (GL_COLOR_ATTACHMENT0_EXT + attachmentIndex));
- mColorAttachmentsForRender.push_back(colorAttachment);
+ invalidateColorAttachmentCache = true;
}
}
- mInvalidateColorAttachmentCache = false;
- return mColorAttachmentsForRender;
-}
-
-gl::Error GetAttachmentRenderTarget(const gl::FramebufferAttachment *attachment, RenderTargetD3D **outRT)
-{
- if (attachment->type() == GL_TEXTURE)
- {
- gl::Texture *texture = attachment->getTexture();
- ASSERT(texture);
- TextureD3D *textureD3D = GetImplAs<TextureD3D>(texture);
- const gl::ImageIndex *index = attachment->getTextureImageIndex();
- ASSERT(index);
- return textureD3D->getRenderTarget(*index, outRT);
- }
- else if (attachment->type() == GL_RENDERBUFFER)
+ if (!invalidateColorAttachmentCache)
{
- gl::Renderbuffer *renderbuffer = attachment->getRenderbuffer();
- ASSERT(renderbuffer);
- RenderbufferD3D *renderbufferD3D = RenderbufferD3D::makeRenderbufferD3D(renderbuffer->getImplementation());
- *outRT = renderbufferD3D->getRenderTarget();
- return gl::Error(GL_NO_ERROR);
+ return;
}
- else if (attachment->type() == GL_FRAMEBUFFER_DEFAULT)
- {
- const gl::DefaultAttachment *defaultAttachment = static_cast<const gl::DefaultAttachment *>(attachment);
- const egl::Surface *surface = defaultAttachment->getSurface();
- ASSERT(surface);
- const SurfaceD3D *surfaceD3D = GetImplAs<SurfaceD3D>(surface);
- ASSERT(surfaceD3D);
- if (defaultAttachment->getBinding() == GL_BACK)
- {
- *outRT = surfaceD3D->getSwapChain()->getColorRenderTarget();
- }
- else
- {
- *outRT = surfaceD3D->getSwapChain()->getDepthStencilRenderTarget();
- }
- return gl::Error(GL_NO_ERROR);
- }
- else
- {
- UNREACHABLE();
- return gl::Error(GL_INVALID_OPERATION);
- }
-}
+ // Does not actually free memory
+ gl::AttachmentList colorAttachmentsForRender;
-// Note: RenderTarget serials should ideally be in the RenderTargets themselves.
-unsigned int GetAttachmentSerial(const gl::FramebufferAttachment *attachment)
-{
- if (attachment->type() == GL_TEXTURE)
- {
- gl::Texture *texture = attachment->getTexture();
- ASSERT(texture);
- TextureD3D *textureD3D = GetImplAs<TextureD3D>(texture);
- const gl::ImageIndex *index = attachment->getTextureImageIndex();
- ASSERT(index);
- return textureD3D->getRenderTargetSerial(*index);
- }
- else if (attachment->type() == GL_RENDERBUFFER)
- {
- gl::Renderbuffer *renderbuffer = attachment->getRenderbuffer();
- ASSERT(renderbuffer);
- RenderbufferD3D *renderbufferD3D = RenderbufferD3D::makeRenderbufferD3D(renderbuffer->getImplementation());
- return renderbufferD3D->getRenderTargetSerial();
- }
- else if (attachment->type() == GL_FRAMEBUFFER_DEFAULT)
+ const auto &colorAttachments = mData.getColorAttachments();
+ const auto &drawBufferStates = mData.getDrawBufferStates();
+ const auto &workarounds = mRenderer->getWorkarounds();
+
+ for (size_t attachmentIndex = 0; attachmentIndex < colorAttachments.size(); ++attachmentIndex)
{
- const gl::DefaultAttachment *defaultAttachment = static_cast<const gl::DefaultAttachment *>(attachment);
- const egl::Surface *surface = defaultAttachment->getSurface();
- ASSERT(surface);
- const SurfaceD3D *surfaceD3D = GetImplAs<SurfaceD3D>(surface);
- ASSERT(surfaceD3D);
+ GLenum drawBufferState = drawBufferStates[attachmentIndex];
+ const gl::FramebufferAttachment &colorAttachment = colorAttachments[attachmentIndex];
- if (defaultAttachment->getBinding() == GL_BACK)
+ if (colorAttachment.isAttached() && drawBufferState != GL_NONE)
{
- return surfaceD3D->getSwapChain()->getColorRenderTarget()->getSerial();
+ ASSERT(drawBufferState == GL_BACK || drawBufferState == (GL_COLOR_ATTACHMENT0_EXT + attachmentIndex));
+ colorAttachmentsForRender.push_back(&colorAttachment);
}
- else
+ else if (!workarounds.mrtPerfWorkaround)
{
- return surfaceD3D->getSwapChain()->getDepthStencilRenderTarget()->getSerial();
+ colorAttachmentsForRender.push_back(nullptr);
}
}
- else
- {
- UNREACHABLE();
- return 0;
- }
+
+ mColorAttachmentsForRender = std::move(colorAttachmentsForRender);
}
+const gl::AttachmentList &FramebufferD3D::getColorAttachmentsForRender() const
+{
+ ASSERT(mColorAttachmentsForRender.valid());
+ return mColorAttachmentsForRender.value();
}
+
+} // namespace rx
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/FramebufferD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/FramebufferD3D.h
index d5d2dae8bd..eb839c4364 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/FramebufferD3D.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/FramebufferD3D.h
@@ -12,6 +12,7 @@
#include <vector>
#include <cstdint>
+#include "common/Optional.h"
#include "libANGLE/angletypes.h"
#include "libANGLE/renderer/FramebufferImpl.h"
@@ -19,12 +20,16 @@ namespace gl
{
class FramebufferAttachment;
struct PixelPackState;
+
+typedef std::vector<const FramebufferAttachment *> AttachmentList;
+
}
namespace rx
{
-class RenderTargetD3D;
class RendererD3D;
+class RenderTargetD3D;
+struct WorkaroundsD3D;
struct ClearParameters
{
@@ -55,22 +60,24 @@ class FramebufferD3D : public FramebufferImpl
FramebufferD3D(const gl::Framebuffer::Data &data, RendererD3D *renderer);
virtual ~FramebufferD3D();
- void setColorAttachment(size_t index, const gl::FramebufferAttachment *attachment) override;
- void setDepthAttachment(const gl::FramebufferAttachment *attachment) override;
- void setStencilAttachment(const gl::FramebufferAttachment *attachment) override;
- void setDepthStencilAttachment(const gl::FramebufferAttachment *attachment) override;
-
- void setDrawBuffers(size_t count, const GLenum *buffers) override;
- void setReadBuffer(GLenum buffer) override;
-
- gl::Error invalidate(size_t count, const GLenum *attachments) override;
- gl::Error invalidateSub(size_t count, const GLenum *attachments, const gl::Rectangle &area) override;
-
gl::Error clear(const gl::Data &data, GLbitfield mask) override;
- gl::Error clearBufferfv(const gl::State &state, GLenum buffer, GLint drawbuffer, const GLfloat *values) override;
- gl::Error clearBufferuiv(const gl::State &state, GLenum buffer, GLint drawbuffer, const GLuint *values) override;
- gl::Error clearBufferiv(const gl::State &state, GLenum buffer, GLint drawbuffer, const GLint *values) override;
- gl::Error clearBufferfi(const gl::State &state, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) override;
+ gl::Error clearBufferfv(const gl::Data &data,
+ GLenum buffer,
+ GLint drawbuffer,
+ const GLfloat *values) override;
+ gl::Error clearBufferuiv(const gl::Data &data,
+ GLenum buffer,
+ GLint drawbuffer,
+ const GLuint *values) override;
+ gl::Error clearBufferiv(const gl::Data &data,
+ GLenum buffer,
+ GLint drawbuffer,
+ const GLint *values) override;
+ gl::Error clearBufferfi(const gl::Data &data,
+ GLenum buffer,
+ GLint drawbuffer,
+ GLfloat depth,
+ GLint stencil) override;
GLenum getImplementationColorReadFormat() const override;
GLenum getImplementationColorReadType() const override;
@@ -79,32 +86,31 @@ class FramebufferD3D : public FramebufferImpl
gl::Error blit(const gl::State &state, const gl::Rectangle &sourceArea, const gl::Rectangle &destArea,
GLbitfield mask, GLenum filter, const gl::Framebuffer *sourceFramebuffer) override;
- GLenum checkStatus() const override;
+ bool checkStatus() const override;
- const gl::AttachmentList &getColorAttachmentsForRender(const Workarounds &workarounds) const;
+ void syncState(const gl::Framebuffer::DirtyBits &dirtyBits) override;
- protected:
- // Cache variable
- mutable gl::AttachmentList mColorAttachmentsForRender;
- mutable bool mInvalidateColorAttachmentCache;
+ const gl::AttachmentList &getColorAttachmentsForRender() const;
private:
- RendererD3D *const mRenderer;
-
- virtual gl::Error clear(const gl::State &state, const ClearParameters &clearParams) = 0;
+ virtual gl::Error clear(const gl::Data &data, const ClearParameters &clearParams) = 0;
- virtual gl::Error readPixels(const gl::Rectangle &area, GLenum format, GLenum type, size_t outputPitch,
- const gl::PixelPackState &pack, uint8_t *pixels) const = 0;
+ virtual gl::Error readPixelsImpl(const gl::Rectangle &area,
+ GLenum format,
+ GLenum type,
+ size_t outputPitch,
+ const gl::PixelPackState &pack,
+ uint8_t *pixels) const = 0;
virtual gl::Error blit(const gl::Rectangle &sourceArea, const gl::Rectangle &destArea, const gl::Rectangle *scissor,
bool blitRenderTarget, bool blitDepth, bool blitStencil, GLenum filter,
const gl::Framebuffer *sourceFramebuffer) = 0;
virtual GLenum getRenderTargetImplementationFormat(RenderTargetD3D *renderTarget) const = 0;
-};
-gl::Error GetAttachmentRenderTarget(const gl::FramebufferAttachment *attachment, RenderTargetD3D **outRT);
-unsigned int GetAttachmentSerial(const gl::FramebufferAttachment *attachment);
+ RendererD3D *mRenderer;
+ Optional<gl::AttachmentList> mColorAttachmentsForRender;
+};
}
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/HLSLCompiler.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/HLSLCompiler.cpp
index 8961a36ec5..df0257e370 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/HLSLCompiler.cpp
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/HLSLCompiler.cpp
@@ -5,21 +5,20 @@
//
#include "libANGLE/renderer/d3d/HLSLCompiler.h"
-#include "libANGLE/Program.h"
-#include "libANGLE/features.h"
#include "common/utilities.h"
-
+#include "libANGLE/Program.h"
+#include "libANGLE/features.h"
+#include "libANGLE/histogram_macros.h"
#include "third_party/trace_event/trace_event.h"
#ifndef QT_D3DCOMPILER_DLL
#define QT_D3DCOMPILER_DLL D3DCOMPILER_DLL
#endif
-// Definitions local to the translation unit
+#if ANGLE_APPEND_ASSEMBLY_TO_SHADER_DEBUG_INFO == ANGLE_ENABLED
namespace
{
-
#ifdef CREATE_COMPILER_FLAG_INFO
#undef CREATE_COMPILER_FLAG_INFO
#endif
@@ -89,19 +88,8 @@ bool IsCompilerFlagSet(UINT mask, UINT flag)
return isFlagSet;
}
}
-
-const char *GetCompilerFlagName(UINT mask, size_t flagIx)
-{
- const CompilerFlagInfo &flagInfo = CompilerFlagInfos[flagIx];
- if (IsCompilerFlagSet(mask, flagInfo.mFlag))
- {
- return flagInfo.mName;
- }
-
- return nullptr;
-}
-
-}
+} // anonymous namespace
+#endif // ANGLE_APPEND_ASSEMBLY_TO_SHADER_DEBUG_INFO == ANGLE_ENABLED
namespace rx
{
@@ -119,9 +107,10 @@ CompileConfig::CompileConfig(UINT flags, const std::string &name)
}
HLSLCompiler::HLSLCompiler()
- : mD3DCompilerModule(NULL),
- mD3DCompileFunc(NULL),
- mD3DDisassembleFunc(NULL)
+ : mInitialized(false),
+ mD3DCompilerModule(nullptr),
+ mD3DCompileFunc(nullptr),
+ mD3DDisassembleFunc(nullptr)
{
}
@@ -130,9 +119,14 @@ HLSLCompiler::~HLSLCompiler()
release();
}
-bool HLSLCompiler::initialize()
+gl::Error HLSLCompiler::initialize()
{
- TRACE_EVENT0("gpu", "initializeCompiler");
+ if (mInitialized)
+ {
+ return gl::Error(GL_NO_ERROR);
+ }
+
+ TRACE_EVENT0("gpu.angle", "HLSLCompiler::initialize");
#if !defined(ANGLE_ENABLE_WINDOWS_STORE)
#if defined(ANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES)
// Find a D3DCompiler module that had already been loaded based on a predefined list of versions.
@@ -168,6 +162,7 @@ bool HLSLCompiler::initialize()
break;
}
+
if (!mD3DCompilerModule)
{
// Load the version of the D3DCompiler DLL associated with the Direct3D version ANGLE was built with.
@@ -176,8 +171,7 @@ bool HLSLCompiler::initialize()
if (!mD3DCompilerModule)
{
- ERR("No D3D compiler module found - aborting!\n");
- return false;
+ return gl::Error(GL_INVALID_OPERATION, "No D3D compiler module found - aborting!\n");
}
mD3DCompileFunc = reinterpret_cast<pD3DCompile>(GetProcAddress(mD3DCompilerModule, "D3DCompile"));
@@ -189,29 +183,42 @@ bool HLSLCompiler::initialize()
#else
// D3D Shader compiler is linked already into this module, so the export
// can be directly assigned.
- mD3DCompilerModule = NULL;
+ mD3DCompilerModule = nullptr;
mD3DCompileFunc = reinterpret_cast<pD3DCompile>(D3DCompile);
mD3DDisassembleFunc = reinterpret_cast<pD3DDisassemble>(D3DDisassemble);
#endif
- return mD3DCompileFunc != NULL;
+ if (mD3DCompileFunc == nullptr)
+ {
+ return gl::Error(GL_INVALID_OPERATION, "Error finding D3DCompile entry point");
+ }
+
+ mInitialized = true;
+ return gl::Error(GL_NO_ERROR);
}
void HLSLCompiler::release()
{
- if (mD3DCompilerModule)
+ if (mInitialized)
{
FreeLibrary(mD3DCompilerModule);
- mD3DCompilerModule = NULL;
- mD3DCompileFunc = NULL;
- mD3DDisassembleFunc = NULL;
+ mD3DCompilerModule = nullptr;
+ mD3DCompileFunc = nullptr;
+ mD3DDisassembleFunc = nullptr;
+ mInitialized = false;
}
}
gl::Error HLSLCompiler::compileToBinary(gl::InfoLog &infoLog, const std::string &hlsl, const std::string &profile,
const std::vector<CompileConfig> &configs, const D3D_SHADER_MACRO *overrideMacros,
- ID3DBlob **outCompiledBlob, std::string *outDebugInfo) const
+ ID3DBlob **outCompiledBlob, std::string *outDebugInfo)
{
+ gl::Error error = initialize();
+ if (error.isError())
+ {
+ return error;
+ }
+
#if !defined(ANGLE_ENABLE_WINDOWS_STORE)
ASSERT(mD3DCompilerModule);
#endif
@@ -226,15 +233,21 @@ gl::Error HLSLCompiler::compileToBinary(gl::InfoLog &infoLog, const std::string
}
#endif
- const D3D_SHADER_MACRO *macros = overrideMacros ? overrideMacros : NULL;
+ const D3D_SHADER_MACRO *macros = overrideMacros ? overrideMacros : nullptr;
for (size_t i = 0; i < configs.size(); ++i)
{
- ID3DBlob *errorMessage = NULL;
- ID3DBlob *binary = NULL;
+ ID3DBlob *errorMessage = nullptr;
+ ID3DBlob *binary = nullptr;
+ HRESULT result = S_OK;
- HRESULT result = mD3DCompileFunc(hlsl.c_str(), hlsl.length(), gl::g_fakepath, macros, NULL, "main", profile.c_str(),
- configs[i].flags, 0, &binary, &errorMessage);
+ {
+ TRACE_EVENT0("gpu.angle", "D3DCompile");
+ SCOPED_ANGLE_HISTOGRAM_TIMER("GPU.ANGLE.D3DCompileMS");
+ result = mD3DCompileFunc(hlsl.c_str(), hlsl.length(), gl::g_fakepath, macros, nullptr,
+ "main", profile.c_str(), configs[i].flags, 0, &binary,
+ &errorMessage);
+ }
if (errorMessage)
{
@@ -245,13 +258,14 @@ gl::Error HLSLCompiler::compileToBinary(gl::InfoLog &infoLog, const std::string
TRACE("\n%s", hlsl.c_str());
TRACE("\n%s", message.c_str());
- if (message.find("error X3531:") != std::string::npos || // "can't unroll loops marked with loop attribute"
- message.find("error X4014:") != std::string::npos) // "cannot have gradient operations inside loops with divergent flow control",
- // even though it is counter-intuitive to disable unrolling for this error,
- // some very long shaders have trouble deciding which loops to unroll and
- // turning off forced unrolls allows them to compile properly.
+ if ((message.find("error X3531:") != std::string::npos || // "can't unroll loops marked with loop attribute"
+ message.find("error X4014:") != std::string::npos) && // "cannot have gradient operations inside loops with divergent flow control",
+ // even though it is counter-intuitive to disable unrolling for this error,
+ // some very long shaders have trouble deciding which loops to unroll and
+ // turning off forced unrolls allows them to compile properly.
+ macros != nullptr)
{
- macros = NULL; // Disable [loop] and [flatten]
+ macros = nullptr; // Disable [loop] and [flatten]
// Retry without changing compiler flags
i--;
@@ -263,16 +277,16 @@ gl::Error HLSLCompiler::compileToBinary(gl::InfoLog &infoLog, const std::string
{
*outCompiledBlob = binary;
-#if ANGLE_SHADER_DEBUG_INFO == ANGLE_ENABLED
(*outDebugInfo) += "// COMPILER INPUT HLSL BEGIN\n\n" + hlsl + "\n// COMPILER INPUT HLSL END\n";
+
+#if ANGLE_APPEND_ASSEMBLY_TO_SHADER_DEBUG_INFO == ANGLE_ENABLED
(*outDebugInfo) += "\n\n// ASSEMBLY BEGIN\n\n";
(*outDebugInfo) += "// Compiler configuration: " + configs[i].name + "\n// Flags:\n";
for (size_t fIx = 0; fIx < ArraySize(CompilerFlagInfos); ++fIx)
{
- const char *flagName = GetCompilerFlagName(configs[i].flags, fIx);
- if (flagName != nullptr)
+ if (IsCompilerFlagSet(configs[i].flags, CompilerFlagInfos[fIx].mFlag))
{
- (*outDebugInfo) += std::string("// ") + flagName + "\n";
+ (*outDebugInfo) += std::string("// ") + CompilerFlagInfos[fIx].mName + "\n";
}
}
@@ -289,52 +303,65 @@ gl::Error HLSLCompiler::compileToBinary(gl::InfoLog &infoLog, const std::string
}
}
- (*outDebugInfo) += "\n" + disassembleBinary(binary) + "\n// ASSEMBLY END\n";
-#endif
-
+ std::string disassembly;
+ error = disassembleBinary(binary, &disassembly);
+ if (error.isError())
+ {
+ return error;
+ }
+ (*outDebugInfo) += "\n" + disassembly + "\n// ASSEMBLY END\n";
+#endif // ANGLE_APPEND_ASSEMBLY_TO_SHADER_DEBUG_INFO == ANGLE_ENABLED
return gl::Error(GL_NO_ERROR);
}
- else
+
+ if (result == E_OUTOFMEMORY)
{
- if (result == E_OUTOFMEMORY)
- {
- *outCompiledBlob = NULL;
- return gl::Error(GL_OUT_OF_MEMORY, "HLSL compiler had an unexpected failure, result: 0x%X.", result);
- }
+ *outCompiledBlob = nullptr;
+ return gl::Error(GL_OUT_OF_MEMORY, "HLSL compiler had an unexpected failure, result: 0x%X.", result);
+ }
- infoLog.append("Warning: D3D shader compilation failed with %s flags.", configs[i].name.c_str());
+ infoLog << "Warning: D3D shader compilation failed with " << configs[i].name << " flags. ("
+ << profile << ")";
- if (i + 1 < configs.size())
- {
- infoLog.append(" Retrying with %s.\n", configs[i + 1].name.c_str());
- }
+ if (i + 1 < configs.size())
+ {
+ infoLog << " Retrying with " << configs[i + 1].name;
}
}
// None of the configurations succeeded in compiling this shader but the compiler is still intact
- *outCompiledBlob = NULL;
+ *outCompiledBlob = nullptr;
return gl::Error(GL_NO_ERROR);
}
-std::string HLSLCompiler::disassembleBinary(ID3DBlob *shaderBinary) const
+gl::Error HLSLCompiler::disassembleBinary(ID3DBlob *shaderBinary, std::string *disassemblyOut)
{
+ gl::Error error = initialize();
+ if (error.isError())
+ {
+ return error;
+ }
+
// Retrieve disassembly
UINT flags = D3D_DISASM_ENABLE_DEFAULT_VALUE_PRINTS | D3D_DISASM_ENABLE_INSTRUCTION_NUMBERING;
- ID3DBlob *disassembly = NULL;
+ ID3DBlob *disassembly = nullptr;
pD3DDisassemble disassembleFunc = reinterpret_cast<pD3DDisassemble>(mD3DDisassembleFunc);
LPCVOID buffer = shaderBinary->GetBufferPointer();
SIZE_T bufSize = shaderBinary->GetBufferSize();
HRESULT result = disassembleFunc(buffer, bufSize, flags, "", &disassembly);
- std::string asmSrc;
if (SUCCEEDED(result))
{
- asmSrc = reinterpret_cast<const char*>(disassembly->GetBufferPointer());
+ *disassemblyOut = std::string(reinterpret_cast<const char*>(disassembly->GetBufferPointer()));
+ }
+ else
+ {
+ *disassemblyOut = "";
}
SafeRelease(disassembly);
- return asmSrc;
+ return gl::Error(GL_NO_ERROR);
}
-}
+} // namespace rx
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/HLSLCompiler.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/HLSLCompiler.h
index a824952553..3c0d2adcac 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/HLSLCompiler.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/HLSLCompiler.h
@@ -32,18 +32,20 @@ class HLSLCompiler : angle::NonCopyable
HLSLCompiler();
~HLSLCompiler();
- bool initialize();
void release();
// Attempt to compile a HLSL shader using the supplied configurations, may output a NULL compiled blob
// even if no GL errors are returned.
gl::Error compileToBinary(gl::InfoLog &infoLog, const std::string &hlsl, const std::string &profile,
const std::vector<CompileConfig> &configs, const D3D_SHADER_MACRO *overrideMacros,
- ID3DBlob **outCompiledBlob, std::string *outDebugInfo) const;
+ ID3DBlob **outCompiledBlob, std::string *outDebugInfo);
- std::string disassembleBinary(ID3DBlob* shaderBinary) const;
+ gl::Error disassembleBinary(ID3DBlob *shaderBinary, std::string *disassemblyOut);
private:
+ gl::Error initialize();
+
+ bool mInitialized;
HMODULE mD3DCompilerModule;
pD3DCompile mD3DCompileFunc;
pD3DDisassemble mD3DDisassembleFunc;
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/ImageD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/ImageD3D.cpp
index 4e6f61150a..ead5db6453 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/ImageD3D.cpp
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/ImageD3D.cpp
@@ -13,6 +13,7 @@
#include "libANGLE/Framebuffer.h"
#include "libANGLE/FramebufferAttachment.h"
#include "libANGLE/renderer/d3d/FramebufferD3D.h"
+#include "libANGLE/renderer/d3d/RenderTargetD3D.h"
namespace rx
{
@@ -22,26 +23,10 @@ ImageD3D::ImageD3D()
mHeight(0),
mDepth(0),
mInternalFormat(GL_NONE),
- mTarget(GL_NONE),
mRenderable(false),
+ mTarget(GL_NONE),
mDirty(false)
{
}
-gl::Error ImageD3D::copy(const gl::Offset &destOffset, const gl::Rectangle &sourceArea, const gl::Framebuffer *source)
-{
- gl::FramebufferAttachment *colorbuffer = source->getReadColorbuffer();
- ASSERT(colorbuffer);
-
- RenderTargetD3D *renderTarget = NULL;
- gl::Error error = GetAttachmentRenderTarget(colorbuffer, &renderTarget);
- if (error.isError())
- {
- return error;
- }
-
- ASSERT(renderTarget);
- return copy(destOffset, sourceArea, renderTarget);
-}
-
-}
+} // namespace rx
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/ImageD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/ImageD3D.h
index 0fe88a8f59..2afe1cfabf 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/ImageD3D.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/ImageD3D.h
@@ -60,10 +60,11 @@ class ImageD3D : angle::NonCopyable
virtual gl::Error setManagedSurface2DArray(TextureStorage *storage, int layer, int level) { return gl::Error(GL_NO_ERROR); };
virtual gl::Error copyToStorage(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box &region) = 0;
- virtual gl::Error copy(const gl::Offset &destOffset, const gl::Box &sourceArea,
- const gl::ImageIndex &sourceIndex, TextureStorage *source) = 0;
-
- gl::Error copy(const gl::Offset &destOffset, const gl::Rectangle &sourceArea, const gl::Framebuffer *source);
+ virtual gl::Error copyFromTexStorage(const gl::ImageIndex &imageIndex,
+ TextureStorage *source) = 0;
+ virtual gl::Error copyFromFramebuffer(const gl::Offset &destOffset,
+ const gl::Rectangle &sourceArea,
+ const gl::Framebuffer *source) = 0;
protected:
GLsizei mWidth;
@@ -74,9 +75,6 @@ class ImageD3D : angle::NonCopyable
GLenum mTarget;
bool mDirty;
-
- private:
- virtual gl::Error copy(const gl::Offset &destOffset, const gl::Rectangle &sourceArea, RenderTargetD3D *source) = 0;
};
}
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexBuffer.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexBuffer.h
index 36262f1d09..0b7b28ddf0 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexBuffer.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexBuffer.h
@@ -12,7 +12,6 @@
#include "common/angleutils.h"
#include "libANGLE/Error.h"
-#include "libANGLE/renderer/IndexRangeCache.h"
namespace rx
{
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexDataManager.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexDataManager.cpp
index 7dad269435..f1ba3d3db0 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexDataManager.cpp
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexDataManager.cpp
@@ -8,6 +8,8 @@
// runs the Buffer translation process for index buffers.
#include "libANGLE/renderer/d3d/IndexDataManager.h"
+
+#include "common/utilities.h"
#include "libANGLE/renderer/d3d/BufferD3D.h"
#include "libANGLE/renderer/d3d/IndexBuffer.h"
#include "libANGLE/Buffer.h"
@@ -16,45 +18,111 @@
namespace rx
{
-static void ConvertIndices(GLenum sourceType, GLenum destinationType, const void *input, GLsizei count, void *output)
+namespace
{
- if (sourceType == GL_UNSIGNED_BYTE)
- {
- ASSERT(destinationType == GL_UNSIGNED_SHORT);
- const GLubyte *in = static_cast<const GLubyte*>(input);
- GLushort *out = static_cast<GLushort*>(output);
+template <typename InputT, typename DestT>
+void ConvertIndexArray(const void *input,
+ GLenum sourceType,
+ void *output,
+ GLenum destinationType,
+ GLsizei count,
+ bool usePrimitiveRestartFixedIndex)
+{
+ const InputT *in = static_cast<const InputT *>(input);
+ DestT *out = static_cast<DestT *>(output);
+
+ if (usePrimitiveRestartFixedIndex)
+ {
+ InputT srcRestartIndex = static_cast<InputT>(gl::GetPrimitiveRestartIndex(sourceType));
+ DestT destRestartIndex = static_cast<DestT>(gl::GetPrimitiveRestartIndex(destinationType));
for (GLsizei i = 0; i < count; i++)
{
- out[i] = in[i];
+ out[i] = (in[i] == srcRestartIndex ? destRestartIndex : static_cast<DestT>(in[i]));
}
}
- else if (sourceType == GL_UNSIGNED_INT)
- {
- ASSERT(destinationType == GL_UNSIGNED_INT);
- memcpy(output, input, count * sizeof(GLuint));
- }
- else if (sourceType == GL_UNSIGNED_SHORT)
+ else
{
- if (destinationType == GL_UNSIGNED_SHORT)
+ for (GLsizei i = 0; i < count; i++)
{
- memcpy(output, input, count * sizeof(GLushort));
+ out[i] = static_cast<DestT>(in[i]);
}
- else if (destinationType == GL_UNSIGNED_INT)
- {
- const GLushort *in = static_cast<const GLushort*>(input);
- GLuint *out = static_cast<GLuint*>(output);
+ }
+}
- for (GLsizei i = 0; i < count; i++)
- {
- out[i] = in[i];
- }
- }
- else UNREACHABLE();
+void ConvertIndices(GLenum sourceType,
+ GLenum destinationType,
+ const void *input,
+ GLsizei count,
+ void *output,
+ bool usePrimitiveRestartFixedIndex)
+{
+ if (sourceType == destinationType)
+ {
+ const gl::Type &typeInfo = gl::GetTypeInfo(destinationType);
+ memcpy(output, input, count * typeInfo.bytes);
+ return;
+ }
+
+ if (sourceType == GL_UNSIGNED_BYTE)
+ {
+ ASSERT(destinationType == GL_UNSIGNED_SHORT);
+ ConvertIndexArray<GLubyte, GLushort>(input, sourceType, output, destinationType, count,
+ usePrimitiveRestartFixedIndex);
+ }
+ else if (sourceType == GL_UNSIGNED_SHORT)
+ {
+ ASSERT(destinationType == GL_UNSIGNED_INT);
+ ConvertIndexArray<GLushort, GLuint>(input, sourceType, output, destinationType, count,
+ usePrimitiveRestartFixedIndex);
}
else UNREACHABLE();
}
+gl::Error StreamInIndexBuffer(IndexBufferInterface *buffer,
+ const GLvoid *data,
+ unsigned int count,
+ GLenum srcType,
+ GLenum dstType,
+ bool usePrimitiveRestartFixedIndex,
+ unsigned int *offset)
+{
+ const gl::Type &dstTypeInfo = gl::GetTypeInfo(dstType);
+
+ if (count > (std::numeric_limits<unsigned int>::max() >> dstTypeInfo.bytesShift))
+ {
+ return gl::Error(GL_OUT_OF_MEMORY,
+ "Reserving %u indices of %u bytes each exceeds the maximum buffer size.",
+ count, dstTypeInfo.bytes);
+ }
+
+ unsigned int bufferSizeRequired = count << dstTypeInfo.bytesShift;
+ gl::Error error = buffer->reserveBufferSpace(bufferSizeRequired, dstType);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ void *output = nullptr;
+ error = buffer->mapBuffer(bufferSizeRequired, &output, offset);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ ConvertIndices(srcType, dstType, data, count, output, usePrimitiveRestartFixedIndex);
+
+ error = buffer->unmapBuffer();
+ if (error.isError())
+ {
+ return error;
+ }
+
+ return gl::Error(GL_NO_ERROR);
+}
+
+} // anonymous namespace
+
IndexDataManager::IndexDataManager(BufferFactoryD3D *factory, RendererClass rendererClass)
: mFactory(factory),
mRendererClass(rendererClass),
@@ -69,163 +137,180 @@ IndexDataManager::~IndexDataManager()
SafeDelete(mStreamingBufferInt);
}
-gl::Error IndexDataManager::prepareIndexData(GLenum type, GLsizei count, gl::Buffer *buffer, const GLvoid *indices, TranslatedIndexData *translated)
+// This function translates a GL-style indices into DX-style indices, with their description
+// returned in translated.
+// GL can specify vertex data in immediate mode (pointer to CPU array of indices), which is not
+// possible in DX and requires streaming (Case 1). If the GL indices are specified with a buffer
+// (Case 2), in a format supported by DX (subcase a) then all is good.
+// When we have a buffer with an unsupported format (subcase b) then we need to do some translation:
+// we will start by falling back to streaming, and after a while will start using a static translated
+// copy of the index buffer.
+gl::Error IndexDataManager::prepareIndexData(GLenum srcType,
+ GLsizei count,
+ gl::Buffer *glBuffer,
+ const GLvoid *indices,
+ TranslatedIndexData *translated,
+ bool primitiveRestartFixedIndexEnabled)
{
- const gl::Type &typeInfo = gl::GetTypeInfo(type);
-
- GLenum destinationIndexType = (type == GL_UNSIGNED_INT) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT;
-
- unsigned int offset = 0;
- bool alignedOffset = false;
-
- BufferD3D *storage = NULL;
-
- if (buffer != NULL)
+ // Avoid D3D11's primitive restart index value
+ // see http://msdn.microsoft.com/en-us/library/windows/desktop/bb205124(v=vs.85).aspx
+ bool hasPrimitiveRestartIndex =
+ translated->indexRange.vertexIndexCount < static_cast<size_t>(count) ||
+ translated->indexRange.end == gl::GetPrimitiveRestartIndex(srcType);
+ bool primitiveRestartWorkaround = mRendererClass == RENDERER_D3D11 &&
+ !primitiveRestartFixedIndexEnabled &&
+ hasPrimitiveRestartIndex && srcType == GL_UNSIGNED_SHORT;
+
+ // We should never have to deal with MAX_UINT indices, since we restrict it via
+ // MAX_ELEMENT_INDEX.
+ ASSERT(!(mRendererClass == RENDERER_D3D11 && !primitiveRestartFixedIndexEnabled &&
+ hasPrimitiveRestartIndex && srcType == GL_UNSIGNED_INT));
+
+ const GLenum dstType = (srcType == GL_UNSIGNED_INT || primitiveRestartWorkaround) ?
+ GL_UNSIGNED_INT : GL_UNSIGNED_SHORT;
+
+ const gl::Type &srcTypeInfo = gl::GetTypeInfo(srcType);
+ const gl::Type &dstTypeInfo = gl::GetTypeInfo(dstType);
+
+ BufferD3D *buffer = glBuffer ? GetImplAs<BufferD3D>(glBuffer) : nullptr;
+
+ translated->indexType = dstType;
+ translated->srcIndexData.srcBuffer = buffer;
+ translated->srcIndexData.srcIndices = indices;
+ translated->srcIndexData.srcIndexType = srcType;
+ translated->srcIndexData.srcCount = count;
+
+ // Case 1: the indices are passed by pointer, which forces the streaming of index data
+ if (glBuffer == nullptr)
{
- offset = static_cast<unsigned int>(reinterpret_cast<uintptr_t>(indices));
-
- storage = GetImplAs<BufferD3D>(buffer);
-
- // We'll trust that the compiler will optimize the % below:
- // the operands are unsigned and the divisor is a constant.
- switch (type)
- {
- case GL_UNSIGNED_BYTE: alignedOffset = (offset % sizeof(GLubyte) == 0); break;
- case GL_UNSIGNED_SHORT: alignedOffset = (offset % sizeof(GLushort) == 0); break;
- case GL_UNSIGNED_INT: alignedOffset = (offset % sizeof(GLuint) == 0); break;
- default: UNREACHABLE(); alignedOffset = false;
- }
-
- ASSERT(typeInfo.bytes * static_cast<unsigned int>(count) + offset <= storage->getSize());
-
- const uint8_t *bufferData = NULL;
- gl::Error error = storage->getData(&bufferData);
- if (error.isError())
- {
- return error;
- }
-
- indices = bufferData + offset;
+ translated->storage = nullptr;
+ return streamIndexData(indices, count, srcType, dstType, primitiveRestartFixedIndexEnabled,
+ translated);
}
- StaticIndexBufferInterface *staticBuffer = storage ? storage->getStaticIndexBuffer() : NULL;
- IndexBufferInterface *indexBuffer = NULL;
- bool directStorage = alignedOffset && storage && storage->supportsDirectBinding() &&
- destinationIndexType == type;
- unsigned int streamOffset = 0;
+ // Case 2: the indices are already in a buffer
+ unsigned int offset = static_cast<unsigned int>(reinterpret_cast<uintptr_t>(indices));
+ ASSERT(srcTypeInfo.bytes * static_cast<unsigned int>(count) + offset <= buffer->getSize());
- if (directStorage)
+ bool offsetAligned;
+ switch (srcType)
{
- streamOffset = offset;
+ case GL_UNSIGNED_BYTE: offsetAligned = (offset % sizeof(GLubyte) == 0); break;
+ case GL_UNSIGNED_SHORT: offsetAligned = (offset % sizeof(GLushort) == 0); break;
+ case GL_UNSIGNED_INT: offsetAligned = (offset % sizeof(GLuint) == 0); break;
+ default: UNREACHABLE(); offsetAligned = false;
}
- else if (staticBuffer && staticBuffer->getBufferSize() != 0 && staticBuffer->getIndexType() == type && alignedOffset)
- {
- indexBuffer = staticBuffer;
- // Using bit-shift here is faster than using division.
- streamOffset = (offset >> typeInfo.bytesShift) << gl::GetTypeInfo(destinationIndexType).bytesShift;
- }
-
- // Avoid D3D11's primitive restart index value
- // see http://msdn.microsoft.com/en-us/library/windows/desktop/bb205124(v=vs.85).aspx
- if (translated->indexRange.end == 0xFFFF && type == GL_UNSIGNED_SHORT && mRendererClass == RENDERER_D3D11)
+ // Case 2a: the buffer can be used directly
+ if (offsetAligned && buffer->supportsDirectBinding() &&
+ dstType == srcType && !primitiveRestartWorkaround)
{
- destinationIndexType = GL_UNSIGNED_INT;
- directStorage = false;
- indexBuffer = NULL;
+ translated->storage = buffer;
+ translated->indexBuffer = nullptr;
+ translated->serial = buffer->getSerial();
+ translated->startIndex = (offset >> srcTypeInfo.bytesShift);
+ translated->startOffset = offset;
+ buffer->promoteStaticUsage(count << srcTypeInfo.bytesShift);
+ return gl::Error(GL_NO_ERROR);
}
-
- const gl::Type &destTypeInfo = gl::GetTypeInfo(destinationIndexType);
-
- if (!directStorage && !indexBuffer)
+ else
{
- gl::Error error = getStreamingIndexBuffer(destinationIndexType, &indexBuffer);
- if (error.isError())
- {
- return error;
- }
-
- unsigned int convertCount = count;
+ translated->storage = nullptr;
+ }
- if (staticBuffer)
- {
- if (staticBuffer->getBufferSize() == 0 && alignedOffset)
- {
- indexBuffer = staticBuffer;
- // Using bit-shift here is faster than using division.
- convertCount = storage->getSize() >> typeInfo.bytesShift;
- }
- else
- {
- storage->invalidateStaticData();
- staticBuffer = NULL;
- }
- }
+ // Case 2b: use a static translated copy or fall back to streaming
+ StaticIndexBufferInterface *staticBuffer = buffer->getStaticIndexBuffer();
- ASSERT(indexBuffer);
+ bool staticBufferInitialized = staticBuffer && staticBuffer->getBufferSize() != 0;
+ bool staticBufferUsable = staticBuffer &&
+ offsetAligned && staticBuffer->getIndexType() == dstType;
- // Using bit-shift here is faster than using division.
- if (convertCount > (std::numeric_limits<unsigned int>::max() >> destTypeInfo.bytesShift))
- {
- return gl::Error(GL_OUT_OF_MEMORY, "Reserving %u indices of %u bytes each exceeds the maximum buffer size.",
- convertCount, destTypeInfo.bytes);
- }
+ if (staticBufferInitialized && !staticBufferUsable)
+ {
+ buffer->invalidateStaticData(D3D_BUFFER_INVALIDATE_WHOLE_CACHE);
+ staticBuffer = nullptr;
+ }
- unsigned int bufferSizeRequired = convertCount << destTypeInfo.bytesShift;
- error = indexBuffer->reserveBufferSpace(bufferSizeRequired, type);
+ if (staticBuffer == nullptr || !offsetAligned)
+ {
+ const uint8_t *bufferData = nullptr;
+ gl::Error error = buffer->getData(&bufferData);
if (error.isError())
{
return error;
}
+ ASSERT(bufferData != nullptr);
- void* output = NULL;
- error = indexBuffer->mapBuffer(bufferSizeRequired, &output, &streamOffset);
+ error = streamIndexData(bufferData + offset, count, srcType, dstType,
+ primitiveRestartFixedIndexEnabled, translated);
if (error.isError())
{
return error;
}
-
- const uint8_t *dataPointer = reinterpret_cast<const uint8_t*>(indices);
- if (staticBuffer)
+ }
+ else
+ {
+ if (!staticBufferInitialized)
{
- error = storage->getData(&dataPointer);
+ const uint8_t *bufferData = nullptr;
+ gl::Error error = buffer->getData(&bufferData);
if (error.isError())
{
return error;
}
- }
- ConvertIndices(type, destinationIndexType, dataPointer, convertCount, output);
+ ASSERT(bufferData != nullptr);
- error = indexBuffer->unmapBuffer();
- if (error.isError())
- {
- return error;
+ unsigned int convertCount =
+ static_cast<unsigned int>(buffer->getSize()) >> srcTypeInfo.bytesShift;
+ error = StreamInIndexBuffer(staticBuffer, bufferData, convertCount, srcType, dstType,
+ primitiveRestartFixedIndexEnabled, nullptr);
+ if (error.isError())
+ {
+ return error;
+ }
}
+ ASSERT(offsetAligned && staticBuffer->getIndexType() == dstType);
- if (staticBuffer)
- {
- // Using bit-shift here is faster than using division.
- streamOffset = (offset >> typeInfo.bytesShift) << destTypeInfo.bytesShift;
- }
+ translated->indexBuffer = staticBuffer->getIndexBuffer();
+ translated->serial = staticBuffer->getSerial();
+ translated->startIndex = (offset >> srcTypeInfo.bytesShift);
+ translated->startOffset = (offset >> srcTypeInfo.bytesShift) << dstTypeInfo.bytesShift;
}
- translated->storage = directStorage ? storage : NULL;
- translated->indexBuffer = indexBuffer ? indexBuffer->getIndexBuffer() : NULL;
- translated->serial = directStorage ? storage->getSerial() : indexBuffer->getSerial();
- // Using bit-shift here is faster than using division.
- translated->startIndex = (streamOffset >> destTypeInfo.bytesShift);
- translated->startOffset = streamOffset;
- translated->indexType = destinationIndexType;
+ return gl::Error(GL_NO_ERROR);
+}
- if (storage)
+gl::Error IndexDataManager::streamIndexData(const GLvoid *data,
+ unsigned int count,
+ GLenum srcType,
+ GLenum dstType,
+ bool usePrimitiveRestartFixedIndex,
+ TranslatedIndexData *translated)
+{
+ const gl::Type &dstTypeInfo = gl::GetTypeInfo(dstType);
+
+ IndexBufferInterface *indexBuffer = nullptr;
+ gl::Error error = getStreamingIndexBuffer(dstType, &indexBuffer);
+ if (error.isError())
{
- storage->promoteStaticUsage(count << typeInfo.bytesShift);
+ return error;
}
+ ASSERT(indexBuffer != nullptr);
+
+ unsigned int offset;
+ StreamInIndexBuffer(indexBuffer, data, count, srcType, dstType, usePrimitiveRestartFixedIndex,
+ &offset);
+
+ translated->indexBuffer = indexBuffer->getIndexBuffer();
+ translated->serial = indexBuffer->getSerial();
+ translated->startIndex = (offset >> dstTypeInfo.bytesShift);
+ translated->startOffset = offset;
return gl::Error(GL_NO_ERROR);
}
-gl::Error IndexDataManager::getStreamingIndexBuffer(GLenum destinationIndexType, IndexBufferInterface **outBuffer)
+gl::Error IndexDataManager::getStreamingIndexBuffer(GLenum destinationIndexType,
+ IndexBufferInterface **outBuffer)
{
ASSERT(outBuffer);
if (destinationIndexType == GL_UNSIGNED_INT)
@@ -233,7 +318,8 @@ gl::Error IndexDataManager::getStreamingIndexBuffer(GLenum destinationIndexType,
if (!mStreamingBufferInt)
{
mStreamingBufferInt = new StreamingIndexBufferInterface(mFactory);
- gl::Error error = mStreamingBufferInt->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_INT);
+ gl::Error error = mStreamingBufferInt->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE,
+ GL_UNSIGNED_INT);
if (error.isError())
{
SafeDelete(mStreamingBufferInt);
@@ -251,7 +337,8 @@ gl::Error IndexDataManager::getStreamingIndexBuffer(GLenum destinationIndexType,
if (!mStreamingBufferShort)
{
mStreamingBufferShort = new StreamingIndexBufferInterface(mFactory);
- gl::Error error = mStreamingBufferShort->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_SHORT);
+ gl::Error error = mStreamingBufferShort->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE,
+ GL_UNSIGNED_SHORT);
if (error.isError())
{
SafeDelete(mStreamingBufferShort);
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexDataManager.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexDataManager.h
index 275b3720c5..44eb68c071 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexDataManager.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexDataManager.h
@@ -36,9 +36,18 @@ class IndexBuffer;
class BufferD3D;
class RendererD3D;
+struct SourceIndexData
+{
+ BufferD3D *srcBuffer;
+ const GLvoid *srcIndices;
+ unsigned int srcCount;
+ GLenum srcIndexType;
+ bool srcIndicesChanged;
+};
+
struct TranslatedIndexData
{
- RangeUI indexRange;
+ gl::IndexRange indexRange;
unsigned int startIndex;
unsigned int startOffset; // In bytes
@@ -46,6 +55,8 @@ struct TranslatedIndexData
BufferD3D *storage;
GLenum indexType;
unsigned int serial;
+
+ SourceIndexData srcIndexData;
};
class IndexDataManager : angle::NonCopyable
@@ -54,10 +65,22 @@ class IndexDataManager : angle::NonCopyable
explicit IndexDataManager(BufferFactoryD3D *factory, RendererClass rendererClass);
virtual ~IndexDataManager();
- gl::Error prepareIndexData(GLenum type, GLsizei count, gl::Buffer *arrayElementBuffer, const GLvoid *indices, TranslatedIndexData *translated);
+ gl::Error prepareIndexData(GLenum srcType,
+ GLsizei count,
+ gl::Buffer *glBuffer,
+ const GLvoid *indices,
+ TranslatedIndexData *translated,
+ bool primitiveRestartFixedIndexEnabled);
private:
- gl::Error getStreamingIndexBuffer(GLenum destinationIndexType, IndexBufferInterface **outBuffer);
+ gl::Error streamIndexData(const GLvoid *data,
+ unsigned int count,
+ GLenum srcType,
+ GLenum dstType,
+ bool usePrimitiveRestartFixedIndex,
+ TranslatedIndexData *translated);
+ gl::Error getStreamingIndexBuffer(GLenum destinationIndexType,
+ IndexBufferInterface **outBuffer);
BufferFactoryD3D *const mFactory;
RendererClass mRendererClass;
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/ProgramD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/ProgramD3D.cpp
index 9ce9a27cd3..72c6f1a1a9 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/ProgramD3D.cpp
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/ProgramD3D.cpp
@@ -8,16 +8,19 @@
#include "libANGLE/renderer/d3d/ProgramD3D.h"
+#include "common/BitSetIterator.h"
#include "common/utilities.h"
#include "libANGLE/Framebuffer.h"
#include "libANGLE/FramebufferAttachment.h"
#include "libANGLE/Program.h"
+#include "libANGLE/VertexArray.h"
#include "libANGLE/features.h"
#include "libANGLE/renderer/d3d/DynamicHLSL.h"
#include "libANGLE/renderer/d3d/FramebufferD3D.h"
#include "libANGLE/renderer/d3d/RendererD3D.h"
#include "libANGLE/renderer/d3d/ShaderD3D.h"
#include "libANGLE/renderer/d3d/ShaderExecutableD3D.h"
+#include "libANGLE/renderer/d3d/VaryingPacking.h"
#include "libANGLE/renderer/d3d/VertexDataManager.h"
namespace rx
@@ -26,69 +29,41 @@ namespace rx
namespace
{
-GLenum GetTextureType(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_3D:
- case GL_INT_SAMPLER_3D:
- case GL_UNSIGNED_INT_SAMPLER_3D:
- return GL_TEXTURE_3D;
- case GL_SAMPLER_CUBE:
- case GL_SAMPLER_CUBE_SHADOW:
- return GL_TEXTURE_CUBE_MAP;
- case GL_INT_SAMPLER_CUBE:
- case GL_UNSIGNED_INT_SAMPLER_CUBE:
- 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;
- default: UNREACHABLE();
- }
-
- return GL_TEXTURE_2D;
-}
-
-void GetDefaultInputLayoutFromShader(const std::vector<sh::Attribute> &shaderAttributes, gl::VertexFormat inputLayout[gl::MAX_VERTEX_ATTRIBS])
+gl::InputLayout GetDefaultInputLayoutFromShader(const gl::Shader *vertexShader)
{
- size_t layoutIndex = 0;
- for (size_t attributeIndex = 0; attributeIndex < shaderAttributes.size(); attributeIndex++)
+ gl::InputLayout defaultLayout;
+ for (const sh::Attribute &shaderAttr : vertexShader->getActiveAttributes())
{
- ASSERT(layoutIndex < gl::MAX_VERTEX_ATTRIBS);
-
- const sh::Attribute &shaderAttr = shaderAttributes[attributeIndex];
-
if (shaderAttr.type != GL_NONE)
{
GLenum transposedType = gl::TransposeMatrixType(shaderAttr.type);
- for (size_t rowIndex = 0; static_cast<int>(rowIndex) < gl::VariableRowCount(transposedType); rowIndex++, layoutIndex++)
+ for (size_t rowIndex = 0;
+ static_cast<int>(rowIndex) < gl::VariableRowCount(transposedType); ++rowIndex)
{
- gl::VertexFormat *defaultFormat = &inputLayout[layoutIndex];
+ GLenum componentType = gl::VariableComponentType(transposedType);
+ GLuint components = static_cast<GLuint>(gl::VariableColumnCount(transposedType));
+ bool pureInt = (componentType != GL_FLOAT);
+ gl::VertexFormatType defaultType =
+ gl::GetVertexFormatType(componentType, GL_FALSE, components, pureInt);
- defaultFormat->mType = gl::VariableComponentType(transposedType);
- defaultFormat->mNormalized = false;
- defaultFormat->mPureInteger = (defaultFormat->mType != GL_FLOAT); // note: inputs can not be bool
- defaultFormat->mComponents = gl::VariableColumnCount(transposedType);
+ defaultLayout.push_back(defaultType);
}
}
}
+
+ return defaultLayout;
}
-std::vector<GLenum> GetDefaultOutputLayoutFromShader(const std::vector<PixelShaderOutputVariable> &shaderOutputVars)
+std::vector<GLenum> GetDefaultOutputLayoutFromShader(
+ const std::vector<PixelShaderOutputVariable> &shaderOutputVars)
{
std::vector<GLenum> defaultPixelOutput;
if (!shaderOutputVars.empty())
{
- defaultPixelOutput.push_back(GL_COLOR_ATTACHMENT0 + shaderOutputVars[0].outputIndex);
+ defaultPixelOutput.push_back(GL_COLOR_ATTACHMENT0 +
+ static_cast<unsigned int>(shaderOutputVars[0].outputIndex));
}
return defaultPixelOutput;
@@ -106,7 +81,7 @@ bool IsRowMajorLayout(const sh::ShaderVariable &var)
struct AttributeSorter
{
- AttributeSorter(const ProgramImpl::SemanticIndexArray &semanticIndices)
+ AttributeSorter(const ProgramD3D::SemanticIndexArray &semanticIndices)
: originalIndices(&semanticIndices)
{
}
@@ -116,26 +91,416 @@ struct AttributeSorter
int indexA = (*originalIndices)[a];
int indexB = (*originalIndices)[b];
- if (indexA == -1) return false;
- if (indexB == -1) return true;
+ if (indexA == -1)
+ return false;
+ if (indexB == -1)
+ return true;
return (indexA < indexB);
}
- const ProgramImpl::SemanticIndexArray *originalIndices;
+ const ProgramD3D::SemanticIndexArray *originalIndices;
};
+// true if varying x has a higher priority in packing than y
+bool ComparePackedVarying(const PackedVarying &x, const PackedVarying &y)
+{
+ return gl::CompareShaderVar(*x.varying, *y.varying);
}
-ProgramD3D::VertexExecutable::VertexExecutable(const gl::VertexFormat inputLayout[],
- const GLenum signature[],
- ShaderExecutableD3D *shaderExecutable)
- : mShaderExecutable(shaderExecutable)
+std::vector<PackedVarying> MergeVaryings(const gl::Shader &vertexShader,
+ const gl::Shader &fragmentShader,
+ const std::vector<std::string> &tfVaryings)
+{
+ std::vector<PackedVarying> packedVaryings;
+
+ for (const sh::Varying &output : vertexShader.getVaryings())
+ {
+ bool packed = false;
+
+ // Built-in varyings obey special rules
+ if (output.isBuiltIn())
+ {
+ continue;
+ }
+
+ for (const sh::Varying &input : fragmentShader.getVaryings())
+ {
+ if (output.name == input.name)
+ {
+ if (output.isStruct())
+ {
+ ASSERT(!output.isArray());
+ for (const auto &field : output.fields)
+ {
+ ASSERT(!field.isStruct() && !field.isArray());
+ packedVaryings.push_back(
+ PackedVarying(field, input.interpolation, input.name));
+ }
+ }
+ else
+ {
+ packedVaryings.push_back(PackedVarying(input, input.interpolation));
+ }
+ packed = true;
+ break;
+ }
+ }
+
+ // Keep Transform FB varyings in the merged list always.
+ if (!packed)
+ {
+ for (const std::string &tfVarying : tfVaryings)
+ {
+ if (tfVarying == output.name)
+ {
+ // Transform feedback for varying structs is underspecified.
+ // See Khronos bug 9856.
+ // TODO(jmadill): Figure out how to be spec-compliant here.
+ if (!output.isStruct())
+ {
+ packedVaryings.push_back(PackedVarying(output, output.interpolation));
+ packedVaryings.back().vertexOnly = true;
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ std::sort(packedVaryings.begin(), packedVaryings.end(), ComparePackedVarying);
+
+ return packedVaryings;
+}
+
+template <typename VarT>
+void GetUniformBlockInfo(const std::vector<VarT> &fields,
+ const std::string &prefix,
+ sh::BlockLayoutEncoder *encoder,
+ bool inRowMajorLayout,
+ std::map<std::string, sh::BlockMemberInfo> *blockInfoOut)
+{
+ for (const VarT &field : fields)
+ {
+ const std::string &fieldName = (prefix.empty() ? field.name : prefix + "." + field.name);
+
+ if (field.isStruct())
+ {
+ bool rowMajorLayout = (inRowMajorLayout || IsRowMajorLayout(field));
+
+ for (unsigned int arrayElement = 0; arrayElement < field.elementCount(); arrayElement++)
+ {
+ encoder->enterAggregateType();
+
+ const std::string uniformElementName =
+ fieldName + (field.isArray() ? ArrayString(arrayElement) : "");
+ GetUniformBlockInfo(field.fields, uniformElementName, encoder, rowMajorLayout,
+ blockInfoOut);
+
+ encoder->exitAggregateType();
+ }
+ }
+ else
+ {
+ bool isRowMajorMatrix = (gl::IsMatrixType(field.type) && inRowMajorLayout);
+ (*blockInfoOut)[fieldName] =
+ encoder->encodeType(field.type, field.arraySize, isRowMajorMatrix);
+ }
+ }
+}
+
+template <typename T>
+static inline void SetIfDirty(T *dest, const T &source, bool *dirtyFlag)
+{
+ ASSERT(dest != NULL);
+ ASSERT(dirtyFlag != NULL);
+
+ *dirtyFlag = *dirtyFlag || (memcmp(dest, &source, sizeof(T)) != 0);
+ *dest = source;
+}
+
+template <typename T>
+bool TransposeMatrix(T *target,
+ const GLfloat *value,
+ int targetWidth,
+ int targetHeight,
+ int srcWidth,
+ int srcHeight)
+{
+ bool dirty = false;
+ int copyWidth = std::min(targetHeight, srcWidth);
+ int copyHeight = std::min(targetWidth, srcHeight);
+
+ for (int x = 0; x < copyWidth; x++)
+ {
+ for (int y = 0; y < copyHeight; y++)
+ {
+ SetIfDirty(target + (x * targetWidth + y), static_cast<T>(value[y * srcWidth + x]),
+ &dirty);
+ }
+ }
+ // clear unfilled right side
+ for (int y = 0; y < copyWidth; y++)
+ {
+ for (int x = copyHeight; x < targetWidth; x++)
+ {
+ SetIfDirty(target + (y * targetWidth + x), static_cast<T>(0), &dirty);
+ }
+ }
+ // clear unfilled bottom.
+ for (int y = copyWidth; y < targetHeight; y++)
+ {
+ for (int x = 0; x < targetWidth; x++)
+ {
+ SetIfDirty(target + (y * targetWidth + x), static_cast<T>(0), &dirty);
+ }
+ }
+
+ return dirty;
+}
+
+template <typename T>
+bool ExpandMatrix(T *target,
+ const GLfloat *value,
+ int targetWidth,
+ int targetHeight,
+ int srcWidth,
+ int srcHeight)
{
- for (size_t attributeIndex = 0; attributeIndex < gl::MAX_VERTEX_ATTRIBS; attributeIndex++)
+ bool dirty = false;
+ int copyWidth = std::min(targetWidth, srcWidth);
+ int copyHeight = std::min(targetHeight, srcHeight);
+
+ for (int y = 0; y < copyHeight; y++)
+ {
+ for (int x = 0; x < copyWidth; x++)
+ {
+ SetIfDirty(target + (y * targetWidth + x), static_cast<T>(value[y * srcWidth + x]),
+ &dirty);
+ }
+ }
+ // clear unfilled right side
+ for (int y = 0; y < copyHeight; y++)
{
- mInputs[attributeIndex] = inputLayout[attributeIndex];
- mSignature[attributeIndex] = signature[attributeIndex];
+ for (int x = copyWidth; x < targetWidth; x++)
+ {
+ SetIfDirty(target + (y * targetWidth + x), static_cast<T>(0), &dirty);
+ }
}
+ // clear unfilled bottom.
+ for (int y = copyHeight; y < targetHeight; y++)
+ {
+ for (int x = 0; x < targetWidth; x++)
+ {
+ SetIfDirty(target + (y * targetWidth + x), static_cast<T>(0), &dirty);
+ }
+ }
+
+ return dirty;
+}
+
+gl::PrimitiveType GetGeometryShaderTypeFromDrawMode(GLenum drawMode)
+{
+ switch (drawMode)
+ {
+ // Uses the point sprite geometry shader.
+ case GL_POINTS:
+ return gl::PRIMITIVE_POINTS;
+
+ // All line drawing uses the same geometry shader.
+ case GL_LINES:
+ case GL_LINE_STRIP:
+ case GL_LINE_LOOP:
+ return gl::PRIMITIVE_LINES;
+
+ // The triangle fan primitive is emulated with strips in D3D11.
+ case GL_TRIANGLES:
+ case GL_TRIANGLE_FAN:
+ return gl::PRIMITIVE_TRIANGLES;
+
+ // Special case for triangle strips.
+ case GL_TRIANGLE_STRIP:
+ return gl::PRIMITIVE_TRIANGLE_STRIP;
+
+ default:
+ UNREACHABLE();
+ return gl::PRIMITIVE_TYPE_MAX;
+ }
+}
+
+} // anonymous namespace
+
+// D3DUniform Implementation
+
+D3DUniform::D3DUniform(GLenum typeIn,
+ const std::string &nameIn,
+ unsigned int arraySizeIn,
+ bool defaultBlock)
+ : type(typeIn),
+ name(nameIn),
+ arraySize(arraySizeIn),
+ data(nullptr),
+ dirty(true),
+ vsRegisterIndex(GL_INVALID_INDEX),
+ psRegisterIndex(GL_INVALID_INDEX),
+ registerCount(0),
+ registerElement(0)
+{
+ // We use data storage for default block uniforms to cache values that are sent to D3D during
+ // rendering
+ // Uniform blocks/buffers are treated separately by the Renderer (ES3 path only)
+ if (defaultBlock)
+ {
+ size_t bytes = gl::VariableInternalSize(type) * elementCount();
+ data = new uint8_t[bytes];
+ memset(data, 0, bytes);
+
+ // TODO(jmadill): is this correct with non-square matrices?
+ registerCount = gl::VariableRowCount(type) * elementCount();
+ }
+}
+
+D3DUniform::~D3DUniform()
+{
+ SafeDeleteArray(data);
+}
+
+bool D3DUniform::isSampler() const
+{
+ return gl::IsSamplerType(type);
+}
+
+bool D3DUniform::isReferencedByVertexShader() const
+{
+ return vsRegisterIndex != GL_INVALID_INDEX;
+}
+
+bool D3DUniform::isReferencedByFragmentShader() const
+{
+ return psRegisterIndex != GL_INVALID_INDEX;
+}
+
+// D3DVarying Implementation
+
+D3DVarying::D3DVarying() : semanticIndex(0), componentCount(0), outputSlot(0)
+{
+}
+
+D3DVarying::D3DVarying(const std::string &semanticNameIn,
+ unsigned int semanticIndexIn,
+ unsigned int componentCountIn,
+ unsigned int outputSlotIn)
+ : semanticName(semanticNameIn),
+ semanticIndex(semanticIndexIn),
+ componentCount(componentCountIn),
+ outputSlot(outputSlotIn)
+{
+}
+
+// ProgramD3DMetadata Implementation
+
+ProgramD3DMetadata::ProgramD3DMetadata(int rendererMajorShaderModel,
+ const std::string &shaderModelSuffix,
+ bool usesInstancedPointSpriteEmulation,
+ bool usesViewScale,
+ const ShaderD3D *vertexShader,
+ const ShaderD3D *fragmentShader)
+ : mRendererMajorShaderModel(rendererMajorShaderModel),
+ mShaderModelSuffix(shaderModelSuffix),
+ mUsesInstancedPointSpriteEmulation(usesInstancedPointSpriteEmulation),
+ mUsesViewScale(usesViewScale),
+ mVertexShader(vertexShader),
+ mFragmentShader(fragmentShader)
+{
+}
+
+int ProgramD3DMetadata::getRendererMajorShaderModel() const
+{
+ return mRendererMajorShaderModel;
+}
+
+bool ProgramD3DMetadata::usesBroadcast(const gl::Data &data) const
+{
+ return (mFragmentShader->usesFragColor() && data.clientVersion < 3);
+}
+
+bool ProgramD3DMetadata::usesFragDepth(const gl::Program::Data &programData) const
+{
+ return mFragmentShader->usesFragDepth();
+}
+
+bool ProgramD3DMetadata::usesPointCoord() const
+{
+ return mFragmentShader->usesPointCoord();
+}
+
+bool ProgramD3DMetadata::usesFragCoord() const
+{
+ return mFragmentShader->usesFragCoord();
+}
+
+bool ProgramD3DMetadata::usesPointSize() const
+{
+ return mVertexShader->usesPointSize();
+}
+
+bool ProgramD3DMetadata::usesInsertedPointCoordValue() const
+{
+ return !usesPointSize() && usesPointCoord() && mRendererMajorShaderModel >= 4;
+}
+
+bool ProgramD3DMetadata::usesViewScale() const
+{
+ return mUsesViewScale;
+}
+
+bool ProgramD3DMetadata::addsPointCoordToVertexShader() const
+{
+ // Instanced PointSprite emulation requires that gl_PointCoord is present in the vertex shader
+ // VS_OUTPUT structure to ensure compatibility with the generated PS_INPUT of the pixel shader.
+ // GeometryShader PointSprite emulation does not require this additional entry because the
+ // GS_OUTPUT of the Geometry shader contains the pointCoord value and already matches the
+ // PS_INPUT of the generated pixel shader. The Geometry Shader point sprite implementation needs
+ // gl_PointSize to be in VS_OUTPUT and GS_INPUT. Instanced point sprites doesn't need
+ // gl_PointSize in VS_OUTPUT.
+ return (mUsesInstancedPointSpriteEmulation && usesPointCoord()) ||
+ usesInsertedPointCoordValue();
+}
+
+bool ProgramD3DMetadata::usesTransformFeedbackGLPosition() const
+{
+ // gl_Position only needs to be outputted from the vertex shader if transform feedback is
+ // active. This isn't supported on D3D11 Feature Level 9_3, so we don't output gl_Position from
+ // the vertex shader in this case. This saves us 1 output vector.
+ return !(mRendererMajorShaderModel >= 4 && mShaderModelSuffix != "");
+}
+
+bool ProgramD3DMetadata::usesSystemValuePointSize() const
+{
+ return !mUsesInstancedPointSpriteEmulation && usesPointSize();
+}
+
+bool ProgramD3DMetadata::usesMultipleFragmentOuts() const
+{
+ return mFragmentShader->usesMultipleRenderTargets();
+}
+
+GLint ProgramD3DMetadata::getMajorShaderVersion() const
+{
+ return mVertexShader->getData().getShaderVersion();
+}
+
+const ShaderD3D *ProgramD3DMetadata::getFragmentShader() const
+{
+ return mFragmentShader;
+}
+
+// ProgramD3D Implementation
+
+ProgramD3D::VertexExecutable::VertexExecutable(const gl::InputLayout &inputLayout,
+ const Signature &signature,
+ ShaderExecutableD3D *shaderExecutable)
+ : mInputs(inputLayout), mSignature(signature), mShaderExecutable(shaderExecutable)
+{
}
ProgramD3D::VertexExecutable::~VertexExecutable()
@@ -143,22 +508,46 @@ ProgramD3D::VertexExecutable::~VertexExecutable()
SafeDelete(mShaderExecutable);
}
-bool ProgramD3D::VertexExecutable::matchesSignature(const GLenum signature[]) const
+// static
+void ProgramD3D::VertexExecutable::getSignature(RendererD3D *renderer,
+ const gl::InputLayout &inputLayout,
+ Signature *signatureOut)
{
- for (size_t attributeIndex = 0; attributeIndex < gl::MAX_VERTEX_ATTRIBS; attributeIndex++)
+ signatureOut->resize(inputLayout.size());
+
+ for (size_t index = 0; index < inputLayout.size(); ++index)
{
- if (mSignature[attributeIndex] != signature[attributeIndex])
+ gl::VertexFormatType vertexFormatType = inputLayout[index];
+ bool converted = false;
+ if (vertexFormatType != gl::VERTEX_FORMAT_INVALID)
{
- return false;
+ VertexConversionType conversionType =
+ renderer->getVertexConversionType(vertexFormatType);
+ converted = ((conversionType & VERTEX_CONVERT_GPU) != 0);
}
+
+ (*signatureOut)[index] = converted;
+ }
+}
+
+bool ProgramD3D::VertexExecutable::matchesSignature(const Signature &signature) const
+{
+ size_t limit = std::max(mSignature.size(), signature.size());
+ for (size_t index = 0; index < limit; ++index)
+ {
+ // treat undefined indexes as 'not converted'
+ bool a = index < signature.size() ? signature[index] : false;
+ bool b = index < mSignature.size() ? mSignature[index] : false;
+ if (a != b)
+ return false;
}
return true;
}
-ProgramD3D::PixelExecutable::PixelExecutable(const std::vector<GLenum> &outputSignature, ShaderExecutableD3D *shaderExecutable)
- : mOutputSignature(outputSignature),
- mShaderExecutable(shaderExecutable)
+ProgramD3D::PixelExecutable::PixelExecutable(const std::vector<GLenum> &outputSignature,
+ ShaderExecutableD3D *shaderExecutable)
+ : mOutputSignature(outputSignature), mShaderExecutable(shaderExecutable)
{
}
@@ -173,19 +562,18 @@ ProgramD3D::Sampler::Sampler() : active(false), logicalTextureUnit(0), textureTy
unsigned int ProgramD3D::mCurrentSerial = 1;
-ProgramD3D::ProgramD3D(RendererD3D *renderer)
- : ProgramImpl(),
+ProgramD3D::ProgramD3D(const gl::Program::Data &data, RendererD3D *renderer)
+ : ProgramImpl(data),
mRenderer(renderer),
mDynamicHLSL(NULL),
- mGeometryExecutable(NULL),
+ mGeometryExecutables(gl::PRIMITIVE_TYPE_MAX, nullptr),
mUsesPointSize(false),
+ mUsesFlatInterpolation(false),
mVertexUniformStorage(NULL),
mFragmentUniformStorage(NULL),
mUsedVertexSamplerRange(0),
mUsedPixelSamplerRange(0),
mDirtySamplerMapping(true),
- mTextureUnitTypesCache(renderer->getRendererCaps().maxCombinedTextureImageUnits),
- mShaderVersion(100),
mSerial(issueSerial())
{
mDynamicHLSL = new DynamicHLSL(renderer);
@@ -202,8 +590,13 @@ bool ProgramD3D::usesPointSpriteEmulation() const
return mUsesPointSize && mRenderer->getMajorShaderModel() >= 4;
}
-bool ProgramD3D::usesGeometryShader() const
+bool ProgramD3D::usesGeometryShader(GLenum drawMode) const
{
+ if (drawMode != GL_POINTS)
+ {
+ return mUsesFlatInterpolation;
+ }
+
return usesPointSpriteEmulation() && !usesInstancedPointSpriteEmulation();
}
@@ -212,30 +605,34 @@ bool ProgramD3D::usesInstancedPointSpriteEmulation() const
return mRenderer->getWorkarounds().useInstancedPointSpriteEmulation;
}
-GLint ProgramD3D::getSamplerMapping(gl::SamplerType type, unsigned int samplerIndex, const gl::Caps &caps) const
+GLint ProgramD3D::getSamplerMapping(gl::SamplerType type,
+ unsigned int samplerIndex,
+ const gl::Caps &caps) const
{
GLint logicalTextureUnit = -1;
switch (type)
{
- case gl::SAMPLER_PIXEL:
- ASSERT(samplerIndex < caps.maxTextureImageUnits);
- if (samplerIndex < mSamplersPS.size() && mSamplersPS[samplerIndex].active)
- {
- logicalTextureUnit = mSamplersPS[samplerIndex].logicalTextureUnit;
- }
- break;
- case gl::SAMPLER_VERTEX:
- ASSERT(samplerIndex < caps.maxVertexTextureImageUnits);
- if (samplerIndex < mSamplersVS.size() && mSamplersVS[samplerIndex].active)
- {
- logicalTextureUnit = mSamplersVS[samplerIndex].logicalTextureUnit;
- }
- break;
- default: UNREACHABLE();
+ case gl::SAMPLER_PIXEL:
+ ASSERT(samplerIndex < caps.maxTextureImageUnits);
+ if (samplerIndex < mSamplersPS.size() && mSamplersPS[samplerIndex].active)
+ {
+ logicalTextureUnit = mSamplersPS[samplerIndex].logicalTextureUnit;
+ }
+ break;
+ case gl::SAMPLER_VERTEX:
+ ASSERT(samplerIndex < caps.maxVertexTextureImageUnits);
+ if (samplerIndex < mSamplersVS.size() && mSamplersVS[samplerIndex].active)
+ {
+ logicalTextureUnit = mSamplersVS[samplerIndex].logicalTextureUnit;
+ }
+ break;
+ default:
+ UNREACHABLE();
}
- if (logicalTextureUnit >= 0 && logicalTextureUnit < static_cast<GLint>(caps.maxCombinedTextureImageUnits))
+ if (logicalTextureUnit >= 0 &&
+ logicalTextureUnit < static_cast<GLint>(caps.maxCombinedTextureImageUnits))
{
return logicalTextureUnit;
}
@@ -249,15 +646,16 @@ GLenum ProgramD3D::getSamplerTextureType(gl::SamplerType type, unsigned int samp
{
switch (type)
{
- case gl::SAMPLER_PIXEL:
- ASSERT(samplerIndex < mSamplersPS.size());
- ASSERT(mSamplersPS[samplerIndex].active);
- return mSamplersPS[samplerIndex].textureType;
- case gl::SAMPLER_VERTEX:
- ASSERT(samplerIndex < mSamplersVS.size());
- ASSERT(mSamplersVS[samplerIndex].active);
- return mSamplersVS[samplerIndex].textureType;
- default: UNREACHABLE();
+ case gl::SAMPLER_PIXEL:
+ ASSERT(samplerIndex < mSamplersPS.size());
+ ASSERT(mSamplersPS[samplerIndex].active);
+ return mSamplersPS[samplerIndex].textureType;
+ case gl::SAMPLER_VERTEX:
+ ASSERT(samplerIndex < mSamplersVS.size());
+ ASSERT(mSamplersVS[samplerIndex].active);
+ return mSamplersVS[samplerIndex].textureType;
+ default:
+ UNREACHABLE();
}
return GL_TEXTURE_2D;
@@ -267,13 +665,13 @@ GLint ProgramD3D::getUsedSamplerRange(gl::SamplerType type) const
{
switch (type)
{
- case gl::SAMPLER_PIXEL:
- return mUsedPixelSamplerRange;
- case gl::SAMPLER_VERTEX:
- return mUsedVertexSamplerRange;
- default:
- UNREACHABLE();
- return 0;
+ case gl::SAMPLER_PIXEL:
+ return mUsedPixelSamplerRange;
+ case gl::SAMPLER_VERTEX:
+ return mUsedVertexSamplerRange;
+ default:
+ UNREACHABLE();
+ return 0;
}
}
@@ -287,145 +685,78 @@ void ProgramD3D::updateSamplerMapping()
mDirtySamplerMapping = false;
// Retrieve sampler uniform values
- for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
+ for (const D3DUniform *d3dUniform : mD3DUniforms)
{
- gl::LinkedUniform *targetUniform = mUniforms[uniformIndex];
-
- if (targetUniform->dirty)
- {
- if (gl::IsSamplerType(targetUniform->type))
- {
- int count = targetUniform->elementCount();
- GLint (*v)[4] = reinterpret_cast<GLint(*)[4]>(targetUniform->data);
-
- if (targetUniform->isReferencedByFragmentShader())
- {
- unsigned int firstIndex = targetUniform->psRegisterIndex;
-
- for (int i = 0; i < count; i++)
- {
- unsigned int samplerIndex = firstIndex + i;
-
- if (samplerIndex < mSamplersPS.size())
- {
- ASSERT(mSamplersPS[samplerIndex].active);
- mSamplersPS[samplerIndex].logicalTextureUnit = v[i][0];
- }
- }
- }
-
- if (targetUniform->isReferencedByVertexShader())
- {
- unsigned int firstIndex = targetUniform->vsRegisterIndex;
-
- for (int i = 0; i < count; i++)
- {
- unsigned int samplerIndex = firstIndex + i;
-
- if (samplerIndex < mSamplersVS.size())
- {
- ASSERT(mSamplersVS[samplerIndex].active);
- mSamplersVS[samplerIndex].logicalTextureUnit = v[i][0];
- }
- }
- }
- }
- }
- }
-}
+ if (!d3dUniform->dirty)
+ continue;
-bool ProgramD3D::validateSamplers(gl::InfoLog *infoLog, const gl::Caps &caps)
-{
- // if any two active samplers in a program are of different types, but refer to the same
- // texture image unit, and this is the current program, then ValidateProgram will fail, and
- // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
- updateSamplerMapping();
+ if (!d3dUniform->isSampler())
+ continue;
- std::fill(mTextureUnitTypesCache.begin(), mTextureUnitTypesCache.end(), GL_NONE);
+ int count = d3dUniform->elementCount();
+ const GLint(*v)[4] = reinterpret_cast<const GLint(*)[4]>(d3dUniform->data);
- for (unsigned int i = 0; i < mUsedPixelSamplerRange; ++i)
- {
- if (mSamplersPS[i].active)
+ if (d3dUniform->isReferencedByFragmentShader())
{
- unsigned int unit = mSamplersPS[i].logicalTextureUnit;
+ unsigned int firstIndex = d3dUniform->psRegisterIndex;
- if (unit >= caps.maxCombinedTextureImageUnits)
+ for (int i = 0; i < count; i++)
{
- if (infoLog)
- {
- infoLog->append("Sampler uniform (%d) exceeds GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, caps.maxCombinedTextureImageUnits);
- }
+ unsigned int samplerIndex = firstIndex + i;
- return false;
- }
-
- if (mTextureUnitTypesCache[unit] != GL_NONE)
- {
- if (mSamplersPS[i].textureType != mTextureUnitTypesCache[unit])
+ if (samplerIndex < mSamplersPS.size())
{
- if (infoLog)
- {
- infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
- }
-
- return false;
+ ASSERT(mSamplersPS[samplerIndex].active);
+ mSamplersPS[samplerIndex].logicalTextureUnit = v[i][0];
}
}
- else
- {
- mTextureUnitTypesCache[unit] = mSamplersPS[i].textureType;
- }
}
- }
- for (unsigned int i = 0; i < mUsedVertexSamplerRange; ++i)
- {
- if (mSamplersVS[i].active)
+ if (d3dUniform->isReferencedByVertexShader())
{
- unsigned int unit = mSamplersVS[i].logicalTextureUnit;
+ unsigned int firstIndex = d3dUniform->vsRegisterIndex;
- if (unit >= caps.maxCombinedTextureImageUnits)
+ for (int i = 0; i < count; i++)
{
- if (infoLog)
- {
- infoLog->append("Sampler uniform (%d) exceeds GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, caps.maxCombinedTextureImageUnits);
- }
-
- return false;
- }
+ unsigned int samplerIndex = firstIndex + i;
- if (mTextureUnitTypesCache[unit] != GL_NONE)
- {
- if (mSamplersVS[i].textureType != mTextureUnitTypesCache[unit])
+ if (samplerIndex < mSamplersVS.size())
{
- if (infoLog)
- {
- infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
- }
-
- return false;
+ ASSERT(mSamplersVS[samplerIndex].active);
+ mSamplersVS[samplerIndex].logicalTextureUnit = v[i][0];
}
}
- else
- {
- mTextureUnitTypesCache[unit] = mSamplersVS[i].textureType;
- }
}
}
-
- return true;
}
LinkResult ProgramD3D::load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream)
{
+ reset();
+
+ DeviceIdentifier binaryDeviceIdentifier = {0};
+ stream->readBytes(reinterpret_cast<unsigned char *>(&binaryDeviceIdentifier),
+ sizeof(DeviceIdentifier));
+
+ DeviceIdentifier identifier = mRenderer->getAdapterIdentifier();
+ if (memcmp(&identifier, &binaryDeviceIdentifier, sizeof(DeviceIdentifier)) != 0)
+ {
+ infoLog << "Invalid program binary, device configuration has changed.";
+ return LinkResult(false, gl::Error(GL_NO_ERROR));
+ }
+
int compileFlags = stream->readInt<int>();
if (compileFlags != ANGLE_COMPILE_OPTIMIZATION_LEVEL)
{
- infoLog.append("Mismatched compilation flags.");
+ infoLog << "Mismatched compilation flags.";
return LinkResult(false, gl::Error(GL_NO_ERROR));
}
- stream->readInt(&mShaderVersion);
+ // TODO(jmadill): replace MAX_VERTEX_ATTRIBS
+ for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; ++i)
+ {
+ stream->readInt(&mSemanticIndexes[i]);
+ }
const unsigned int psSamplerCount = stream->readInt<unsigned int>();
for (unsigned int i = 0; i < psSamplerCount; ++i)
@@ -452,105 +783,69 @@ LinkResult ProgramD3D::load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream)
const unsigned int uniformCount = stream->readInt<unsigned int>();
if (stream->error())
{
- infoLog.append("Invalid program binary.");
+ infoLog << "Invalid program binary.";
return LinkResult(false, gl::Error(GL_NO_ERROR));
}
- mUniforms.resize(uniformCount);
+ const auto &linkedUniforms = mData.getUniforms();
+ ASSERT(mD3DUniforms.empty());
for (unsigned int uniformIndex = 0; uniformIndex < uniformCount; uniformIndex++)
{
- GLenum type = stream->readInt<GLenum>();
- GLenum precision = stream->readInt<GLenum>();
- std::string name = stream->readString();
- unsigned int arraySize = stream->readInt<unsigned int>();
- int blockIndex = stream->readInt<int>();
-
- int offset = stream->readInt<int>();
- int arrayStride = stream->readInt<int>();
- int matrixStride = stream->readInt<int>();
- bool isRowMajorMatrix = stream->readBool();
-
- const sh::BlockMemberInfo blockInfo(offset, arrayStride, matrixStride, isRowMajorMatrix);
-
- gl::LinkedUniform *uniform = new gl::LinkedUniform(type, precision, name, arraySize, blockIndex, blockInfo);
-
- stream->readInt(&uniform->psRegisterIndex);
- stream->readInt(&uniform->vsRegisterIndex);
- stream->readInt(&uniform->registerCount);
- stream->readInt(&uniform->registerElement);
+ const gl::LinkedUniform &linkedUniform = linkedUniforms[uniformIndex];
- mUniforms[uniformIndex] = uniform;
- }
+ D3DUniform *d3dUniform =
+ new D3DUniform(linkedUniform.type, linkedUniform.name, linkedUniform.arraySize,
+ linkedUniform.isInDefaultBlock());
+ stream->readInt(&d3dUniform->psRegisterIndex);
+ stream->readInt(&d3dUniform->vsRegisterIndex);
+ stream->readInt(&d3dUniform->registerCount);
+ stream->readInt(&d3dUniform->registerElement);
- const unsigned int uniformIndexCount = stream->readInt<unsigned int>();
- if (stream->error())
- {
- infoLog.append("Invalid program binary.");
- return LinkResult(false, gl::Error(GL_NO_ERROR));
- }
-
- mUniformIndex.resize(uniformIndexCount);
- for (unsigned int uniformIndexIndex = 0; uniformIndexIndex < uniformIndexCount; uniformIndexIndex++)
- {
- stream->readString(&mUniformIndex[uniformIndexIndex].name);
- stream->readInt(&mUniformIndex[uniformIndexIndex].element);
- stream->readInt(&mUniformIndex[uniformIndexIndex].index);
+ mD3DUniforms.push_back(d3dUniform);
}
- unsigned int uniformBlockCount = stream->readInt<unsigned int>();
+ const unsigned int blockCount = stream->readInt<unsigned int>();
if (stream->error())
{
- infoLog.append("Invalid program binary.");
+ infoLog << "Invalid program binary.";
return LinkResult(false, gl::Error(GL_NO_ERROR));
}
- mUniformBlocks.resize(uniformBlockCount);
- for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < uniformBlockCount; ++uniformBlockIndex)
+ ASSERT(mD3DUniformBlocks.empty());
+ for (unsigned int blockIndex = 0; blockIndex < blockCount; ++blockIndex)
{
- std::string name = stream->readString();
- unsigned int elementIndex = stream->readInt<unsigned int>();
- unsigned int dataSize = stream->readInt<unsigned int>();
-
- gl::UniformBlock *uniformBlock = new gl::UniformBlock(name, elementIndex, dataSize);
-
- stream->readInt(&uniformBlock->psRegisterIndex);
- stream->readInt(&uniformBlock->vsRegisterIndex);
-
- unsigned int numMembers = stream->readInt<unsigned int>();
- uniformBlock->memberUniformIndexes.resize(numMembers);
- for (unsigned int blockMemberIndex = 0; blockMemberIndex < numMembers; blockMemberIndex++)
- {
- stream->readInt(&uniformBlock->memberUniformIndexes[blockMemberIndex]);
- }
-
- mUniformBlocks[uniformBlockIndex] = uniformBlock;
+ D3DUniformBlock uniformBlock;
+ stream->readInt(&uniformBlock.psRegisterIndex);
+ stream->readInt(&uniformBlock.vsRegisterIndex);
+ mD3DUniformBlocks.push_back(uniformBlock);
}
- stream->readInt(&mTransformFeedbackBufferMode);
- const unsigned int transformFeedbackVaryingCount = stream->readInt<unsigned int>();
- mTransformFeedbackLinkedVaryings.resize(transformFeedbackVaryingCount);
- for (unsigned int varyingIndex = 0; varyingIndex < transformFeedbackVaryingCount; varyingIndex++)
+ const unsigned int streamOutVaryingCount = stream->readInt<unsigned int>();
+ mStreamOutVaryings.resize(streamOutVaryingCount);
+ for (unsigned int varyingIndex = 0; varyingIndex < streamOutVaryingCount; ++varyingIndex)
{
- gl::LinkedVarying &varying = mTransformFeedbackLinkedVaryings[varyingIndex];
+ D3DVarying *varying = &mStreamOutVaryings[varyingIndex];
- stream->readString(&varying.name);
- stream->readInt(&varying.type);
- stream->readInt(&varying.size);
- stream->readString(&varying.semanticName);
- stream->readInt(&varying.semanticIndex);
- stream->readInt(&varying.semanticIndexCount);
+ stream->readString(&varying->semanticName);
+ stream->readInt(&varying->semanticIndex);
+ stream->readInt(&varying->componentCount);
+ stream->readInt(&varying->outputSlot);
}
stream->readString(&mVertexHLSL);
- stream->readBytes(reinterpret_cast<unsigned char*>(&mVertexWorkarounds), sizeof(D3DCompilerWorkarounds));
+ stream->readBytes(reinterpret_cast<unsigned char *>(&mVertexWorkarounds),
+ sizeof(D3DCompilerWorkarounds));
stream->readString(&mPixelHLSL);
- stream->readBytes(reinterpret_cast<unsigned char*>(&mPixelWorkarounds), sizeof(D3DCompilerWorkarounds));
+ stream->readBytes(reinterpret_cast<unsigned char *>(&mPixelWorkarounds),
+ sizeof(D3DCompilerWorkarounds));
stream->readBool(&mUsesFragDepth);
stream->readBool(&mUsesPointSize);
+ stream->readBool(&mUsesFlatInterpolation);
const size_t pixelShaderKeySize = stream->readInt<unsigned int>();
mPixelShaderKey.resize(pixelShaderKeySize);
- for (size_t pixelShaderKeyIndex = 0; pixelShaderKeyIndex < pixelShaderKeySize; pixelShaderKeyIndex++)
+ for (size_t pixelShaderKeyIndex = 0; pixelShaderKeyIndex < pixelShaderKeySize;
+ pixelShaderKeyIndex++)
{
stream->readInt(&mPixelShaderKey[pixelShaderKeyIndex].type);
stream->readString(&mPixelShaderKey[pixelShaderKeyIndex].name);
@@ -558,31 +853,30 @@ LinkResult ProgramD3D::load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream)
stream->readInt(&mPixelShaderKey[pixelShaderKeyIndex].outputIndex);
}
- const unsigned char* binary = reinterpret_cast<const unsigned char*>(stream->data());
+ stream->readString(&mGeometryShaderPreamble);
+
+ const unsigned char *binary = reinterpret_cast<const unsigned char *>(stream->data());
const unsigned int vertexShaderCount = stream->readInt<unsigned int>();
- for (unsigned int vertexShaderIndex = 0; vertexShaderIndex < vertexShaderCount; vertexShaderIndex++)
+ for (unsigned int vertexShaderIndex = 0; vertexShaderIndex < vertexShaderCount;
+ vertexShaderIndex++)
{
- gl::VertexFormat inputLayout[gl::MAX_VERTEX_ATTRIBS];
+ size_t inputLayoutSize = stream->readInt<size_t>();
+ gl::InputLayout inputLayout(inputLayoutSize, gl::VERTEX_FORMAT_INVALID);
- for (size_t inputIndex = 0; inputIndex < gl::MAX_VERTEX_ATTRIBS; inputIndex++)
+ for (size_t inputIndex = 0; inputIndex < inputLayoutSize; inputIndex++)
{
- gl::VertexFormat *vertexInput = &inputLayout[inputIndex];
- stream->readInt(&vertexInput->mType);
- stream->readInt(&vertexInput->mNormalized);
- stream->readInt(&vertexInput->mComponents);
- stream->readBool(&vertexInput->mPureInteger);
+ inputLayout[inputIndex] = stream->readInt<gl::VertexFormatType>();
}
- unsigned int vertexShaderSize = stream->readInt<unsigned int>();
+ unsigned int vertexShaderSize = stream->readInt<unsigned int>();
const unsigned char *vertexShaderFunction = binary + stream->offset();
- ShaderExecutableD3D *shaderExecutable = NULL;
- gl::Error error = mRenderer->loadExecutable(vertexShaderFunction, vertexShaderSize,
- SHADER_VERTEX,
- mTransformFeedbackLinkedVaryings,
- (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS),
- &shaderExecutable);
+ ShaderExecutableD3D *shaderExecutable = nullptr;
+
+ gl::Error error = mRenderer->loadExecutable(
+ vertexShaderFunction, vertexShaderSize, SHADER_VERTEX, mStreamOutVaryings,
+ (mData.getTransformFeedbackBufferMode() == GL_SEPARATE_ATTRIBS), &shaderExecutable);
if (error.isError())
{
return LinkResult(false, error);
@@ -590,16 +884,17 @@ LinkResult ProgramD3D::load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream)
if (!shaderExecutable)
{
- infoLog.append("Could not create vertex shader.");
+ infoLog << "Could not create vertex shader.";
return LinkResult(false, gl::Error(GL_NO_ERROR));
}
// generated converted input layout
- GLenum signature[gl::MAX_VERTEX_ATTRIBS];
- getInputLayoutSignature(inputLayout, signature);
+ VertexExecutable::Signature signature;
+ VertexExecutable::getSignature(mRenderer, inputLayout, &signature);
// add new binary
- mVertexExecutables.push_back(new VertexExecutable(inputLayout, signature, shaderExecutable));
+ mVertexExecutables.push_back(
+ new VertexExecutable(inputLayout, signature, shaderExecutable));
stream->skip(vertexShaderSize);
}
@@ -614,13 +909,13 @@ LinkResult ProgramD3D::load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream)
stream->readInt(&outputs[outputIndex]);
}
- const size_t pixelShaderSize = stream->readInt<unsigned int>();
+ const size_t pixelShaderSize = stream->readInt<unsigned int>();
const unsigned char *pixelShaderFunction = binary + stream->offset();
- ShaderExecutableD3D *shaderExecutable = NULL;
- gl::Error error = mRenderer->loadExecutable(pixelShaderFunction, pixelShaderSize, SHADER_PIXEL,
- mTransformFeedbackLinkedVaryings,
- (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS),
- &shaderExecutable);
+ ShaderExecutableD3D *shaderExecutable = nullptr;
+
+ gl::Error error = mRenderer->loadExecutable(
+ pixelShaderFunction, pixelShaderSize, SHADER_PIXEL, mStreamOutVaryings,
+ (mData.getTransformFeedbackBufferMode() == GL_SEPARATE_ATTRIBS), &shaderExecutable);
if (error.isError())
{
return LinkResult(false, error);
@@ -628,7 +923,7 @@ LinkResult ProgramD3D::load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream)
if (!shaderExecutable)
{
- infoLog.append("Could not create pixel shader.");
+ infoLog << "Could not create pixel shader.";
return LinkResult(false, gl::Error(GL_NO_ERROR));
}
@@ -638,38 +933,35 @@ LinkResult ProgramD3D::load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream)
stream->skip(pixelShaderSize);
}
- unsigned int geometryShaderSize = stream->readInt<unsigned int>();
-
- if (geometryShaderSize > 0)
+ for (unsigned int geometryExeIndex = 0; geometryExeIndex < gl::PRIMITIVE_TYPE_MAX;
+ ++geometryExeIndex)
{
+ unsigned int geometryShaderSize = stream->readInt<unsigned int>();
+ if (geometryShaderSize == 0)
+ {
+ mGeometryExecutables[geometryExeIndex] = nullptr;
+ continue;
+ }
+
const unsigned char *geometryShaderFunction = binary + stream->offset();
- gl::Error error = mRenderer->loadExecutable(geometryShaderFunction, geometryShaderSize, SHADER_GEOMETRY,
- mTransformFeedbackLinkedVaryings,
- (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS),
- &mGeometryExecutable);
+ bool splitAttribs = (mData.getTransformFeedbackBufferMode() == GL_SEPARATE_ATTRIBS);
+
+ gl::Error error = mRenderer->loadExecutable(
+ geometryShaderFunction, geometryShaderSize, SHADER_GEOMETRY, mStreamOutVaryings,
+ splitAttribs, &mGeometryExecutables[geometryExeIndex]);
if (error.isError())
{
return LinkResult(false, error);
}
- if (!mGeometryExecutable)
+ if (!mGeometryExecutables[geometryExeIndex])
{
- infoLog.append("Could not create geometry shader.");
+ infoLog << "Could not create geometry shader.";
return LinkResult(false, gl::Error(GL_NO_ERROR));
}
stream->skip(geometryShaderSize);
}
- GUID binaryIdentifier = {0};
- stream->readBytes(reinterpret_cast<unsigned char*>(&binaryIdentifier), sizeof(GUID));
-
- GUID identifier = mRenderer->getAdapterIdentifier();
- if (memcmp(&identifier, &binaryIdentifier, sizeof(GUID)) != 0)
- {
- infoLog.append("Invalid program binary.");
- return LinkResult(false, gl::Error(GL_NO_ERROR));
- }
-
initializeUniformStorage();
initAttributesByLayout();
@@ -678,9 +970,20 @@ LinkResult ProgramD3D::load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream)
gl::Error ProgramD3D::save(gl::BinaryOutputStream *stream)
{
+ // Output the DeviceIdentifier before we output any shader code
+ // When we load the binary again later, we can validate the device identifier before trying to
+ // compile any HLSL
+ DeviceIdentifier binaryIdentifier = mRenderer->getAdapterIdentifier();
+ stream->writeBytes(reinterpret_cast<unsigned char *>(&binaryIdentifier),
+ sizeof(DeviceIdentifier));
+
stream->writeInt(ANGLE_COMPILE_OPTIMIZATION_LEVEL);
- stream->writeInt(mShaderVersion);
+ // TODO(jmadill): replace MAX_VERTEX_ATTRIBS
+ for (unsigned int i = 0; i < gl::MAX_VERTEX_ATTRIBS; ++i)
+ {
+ stream->writeInt(mSemanticIndexes[i]);
+ }
stream->writeInt(mSamplersPS.size());
for (unsigned int i = 0; i < mSamplersPS.size(); ++i)
@@ -701,79 +1004,46 @@ gl::Error ProgramD3D::save(gl::BinaryOutputStream *stream)
stream->writeInt(mUsedVertexSamplerRange);
stream->writeInt(mUsedPixelSamplerRange);
- stream->writeInt(mUniforms.size());
- for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); ++uniformIndex)
+ stream->writeInt(mD3DUniforms.size());
+ for (const D3DUniform *uniform : mD3DUniforms)
{
- const gl::LinkedUniform &uniform = *mUniforms[uniformIndex];
-
- stream->writeInt(uniform.type);
- stream->writeInt(uniform.precision);
- stream->writeString(uniform.name);
- stream->writeInt(uniform.arraySize);
- stream->writeInt(uniform.blockIndex);
-
- stream->writeInt(uniform.blockInfo.offset);
- stream->writeInt(uniform.blockInfo.arrayStride);
- stream->writeInt(uniform.blockInfo.matrixStride);
- stream->writeInt(uniform.blockInfo.isRowMajorMatrix);
-
- stream->writeInt(uniform.psRegisterIndex);
- stream->writeInt(uniform.vsRegisterIndex);
- stream->writeInt(uniform.registerCount);
- stream->writeInt(uniform.registerElement);
+ // Type, name and arraySize are redundant, so aren't stored in the binary.
+ stream->writeInt(uniform->psRegisterIndex);
+ stream->writeInt(uniform->vsRegisterIndex);
+ stream->writeInt(uniform->registerCount);
+ stream->writeInt(uniform->registerElement);
}
- stream->writeInt(mUniformIndex.size());
- for (size_t i = 0; i < mUniformIndex.size(); ++i)
+ stream->writeInt(mD3DUniformBlocks.size());
+ for (const D3DUniformBlock &uniformBlock : mD3DUniformBlocks)
{
- stream->writeString(mUniformIndex[i].name);
- stream->writeInt(mUniformIndex[i].element);
- stream->writeInt(mUniformIndex[i].index);
- }
-
- stream->writeInt(mUniformBlocks.size());
- for (size_t uniformBlockIndex = 0; uniformBlockIndex < mUniformBlocks.size(); ++uniformBlockIndex)
- {
- const gl::UniformBlock& uniformBlock = *mUniformBlocks[uniformBlockIndex];
-
- stream->writeString(uniformBlock.name);
- stream->writeInt(uniformBlock.elementIndex);
- stream->writeInt(uniformBlock.dataSize);
-
- stream->writeInt(uniformBlock.memberUniformIndexes.size());
- for (unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++)
- {
- stream->writeInt(uniformBlock.memberUniformIndexes[blockMemberIndex]);
- }
-
stream->writeInt(uniformBlock.psRegisterIndex);
stream->writeInt(uniformBlock.vsRegisterIndex);
}
- stream->writeInt(mTransformFeedbackBufferMode);
- stream->writeInt(mTransformFeedbackLinkedVaryings.size());
- for (size_t i = 0; i < mTransformFeedbackLinkedVaryings.size(); i++)
+ stream->writeInt(mStreamOutVaryings.size());
+ for (const auto &varying : mStreamOutVaryings)
{
- const gl::LinkedVarying &varying = mTransformFeedbackLinkedVaryings[i];
-
- stream->writeString(varying.name);
- stream->writeInt(varying.type);
- stream->writeInt(varying.size);
stream->writeString(varying.semanticName);
stream->writeInt(varying.semanticIndex);
- stream->writeInt(varying.semanticIndexCount);
+ stream->writeInt(varying.componentCount);
+ stream->writeInt(varying.outputSlot);
}
stream->writeString(mVertexHLSL);
- stream->writeBytes(reinterpret_cast<unsigned char*>(&mVertexWorkarounds), sizeof(D3DCompilerWorkarounds));
+ stream->writeBytes(reinterpret_cast<unsigned char *>(&mVertexWorkarounds),
+ sizeof(D3DCompilerWorkarounds));
stream->writeString(mPixelHLSL);
- stream->writeBytes(reinterpret_cast<unsigned char*>(&mPixelWorkarounds), sizeof(D3DCompilerWorkarounds));
+ stream->writeBytes(reinterpret_cast<unsigned char *>(&mPixelWorkarounds),
+ sizeof(D3DCompilerWorkarounds));
stream->writeInt(mUsesFragDepth);
stream->writeInt(mUsesPointSize);
+ stream->writeInt(mUsesFlatInterpolation);
const std::vector<PixelShaderOutputVariable> &pixelShaderKey = mPixelShaderKey;
stream->writeInt(pixelShaderKey.size());
- for (size_t pixelShaderKeyIndex = 0; pixelShaderKeyIndex < pixelShaderKey.size(); pixelShaderKeyIndex++)
+ for (size_t pixelShaderKeyIndex = 0; pixelShaderKeyIndex < pixelShaderKey.size();
+ pixelShaderKeyIndex++)
{
const PixelShaderOutputVariable &variable = pixelShaderKey[pixelShaderKeyIndex];
stream->writeInt(variable.type);
@@ -782,18 +1052,20 @@ gl::Error ProgramD3D::save(gl::BinaryOutputStream *stream)
stream->writeInt(variable.outputIndex);
}
+ stream->writeString(mGeometryShaderPreamble);
+
stream->writeInt(mVertexExecutables.size());
- for (size_t vertexExecutableIndex = 0; vertexExecutableIndex < mVertexExecutables.size(); vertexExecutableIndex++)
+ for (size_t vertexExecutableIndex = 0; vertexExecutableIndex < mVertexExecutables.size();
+ vertexExecutableIndex++)
{
VertexExecutable *vertexExecutable = mVertexExecutables[vertexExecutableIndex];
- for (size_t inputIndex = 0; inputIndex < gl::MAX_VERTEX_ATTRIBS; inputIndex++)
+ const auto &inputLayout = vertexExecutable->inputs();
+ stream->writeInt(inputLayout.size());
+
+ for (size_t inputIndex = 0; inputIndex < inputLayout.size(); inputIndex++)
{
- const gl::VertexFormat &vertexInput = vertexExecutable->inputs()[inputIndex];
- stream->writeInt(vertexInput.mType);
- stream->writeInt(vertexInput.mNormalized);
- stream->writeInt(vertexInput.mComponents);
- stream->writeInt(vertexInput.mPureInteger);
+ stream->writeInt(inputLayout[inputIndex]);
}
size_t vertexShaderSize = vertexExecutable->shaderExecutable()->getLength();
@@ -804,7 +1076,8 @@ gl::Error ProgramD3D::save(gl::BinaryOutputStream *stream)
}
stream->writeInt(mPixelExecutables.size());
- for (size_t pixelExecutableIndex = 0; pixelExecutableIndex < mPixelExecutables.size(); pixelExecutableIndex++)
+ for (size_t pixelExecutableIndex = 0; pixelExecutableIndex < mPixelExecutables.size();
+ pixelExecutableIndex++)
{
PixelExecutable *pixelExecutable = mPixelExecutables[pixelExecutableIndex];
@@ -822,27 +1095,33 @@ gl::Error ProgramD3D::save(gl::BinaryOutputStream *stream)
stream->writeBytes(pixelBlob, pixelShaderSize);
}
- size_t geometryShaderSize = (mGeometryExecutable != NULL) ? mGeometryExecutable->getLength() : 0;
- stream->writeInt(geometryShaderSize);
-
- if (mGeometryExecutable != NULL && geometryShaderSize > 0)
+ for (const ShaderExecutableD3D *geometryExe : mGeometryExecutables)
{
- const uint8_t *geometryBlob = mGeometryExecutable->getFunction();
- stream->writeBytes(geometryBlob, geometryShaderSize);
- }
+ if (geometryExe == nullptr)
+ {
+ stream->writeInt(0);
+ continue;
+ }
- GUID binaryIdentifier = mRenderer->getAdapterIdentifier();
- stream->writeBytes(reinterpret_cast<unsigned char*>(&binaryIdentifier), sizeof(GUID));
+ size_t geometryShaderSize = geometryExe->getLength();
+ stream->writeInt(geometryShaderSize);
+ stream->writeBytes(geometryExe->getFunction(), geometryShaderSize);
+ }
return gl::Error(GL_NO_ERROR);
}
-gl::Error ProgramD3D::getPixelExecutableForFramebuffer(const gl::Framebuffer *fbo, ShaderExecutableD3D **outExecutable)
+void ProgramD3D::setBinaryRetrievableHint(bool /* retrievable */)
+{
+}
+
+gl::Error ProgramD3D::getPixelExecutableForFramebuffer(const gl::Framebuffer *fbo,
+ ShaderExecutableD3D **outExecutable)
{
mPixelShaderOutputFormatCache.clear();
const FramebufferD3D *fboD3D = GetImplAs<FramebufferD3D>(fbo);
- const gl::AttachmentList &colorbuffers = fboD3D->getColorAttachmentsForRender(mRenderer->getWorkarounds());
+ const gl::AttachmentList &colorbuffers = fboD3D->getColorAttachmentsForRender();
for (size_t colorAttachment = 0; colorAttachment < colorbuffers.size(); ++colorAttachment)
{
@@ -850,7 +1129,9 @@ gl::Error ProgramD3D::getPixelExecutableForFramebuffer(const gl::Framebuffer *fb
if (colorbuffer)
{
- mPixelShaderOutputFormatCache.push_back(colorbuffer->getBinding() == GL_BACK ? GL_COLOR_ATTACHMENT0 : colorbuffer->getBinding());
+ mPixelShaderOutputFormatCache.push_back(colorbuffer->getBinding() == GL_BACK
+ ? GL_COLOR_ATTACHMENT0
+ : colorbuffer->getBinding());
}
else
{
@@ -874,8 +1155,8 @@ gl::Error ProgramD3D::getPixelExecutableForOutputLayout(const std::vector<GLenum
}
}
- std::string finalPixelHLSL = mDynamicHLSL->generatePixelShaderForOutputSignature(mPixelHLSL, mPixelShaderKey, mUsesFragDepth,
- outputSignature);
+ std::string finalPixelHLSL = mDynamicHLSL->generatePixelShaderForOutputSignature(
+ mPixelHLSL, mPixelShaderKey, mUsesFragDepth, outputSignature);
// Generate new pixel executable
ShaderExecutableD3D *pixelExecutable = NULL;
@@ -883,10 +1164,10 @@ gl::Error ProgramD3D::getPixelExecutableForOutputLayout(const std::vector<GLenum
gl::InfoLog tempInfoLog;
gl::InfoLog *currentInfoLog = infoLog ? infoLog : &tempInfoLog;
- gl::Error error = mRenderer->compileToExecutable(*currentInfoLog, finalPixelHLSL, SHADER_PIXEL,
- mTransformFeedbackLinkedVaryings,
- (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS),
- mPixelWorkarounds, &pixelExecutable);
+ gl::Error error = mRenderer->compileToExecutable(
+ *currentInfoLog, finalPixelHLSL, SHADER_PIXEL, mStreamOutVaryings,
+ (mData.getTransformFeedbackBufferMode() == GL_SEPARATE_ATTRIBS), mPixelWorkarounds,
+ &pixelExecutable);
if (error.isError())
{
return error;
@@ -899,7 +1180,7 @@ gl::Error ProgramD3D::getPixelExecutableForOutputLayout(const std::vector<GLenum
else if (!infoLog)
{
std::vector<char> tempCharBuffer(tempInfoLog.getLength() + 3);
- tempInfoLog.getLog(tempInfoLog.getLength(), NULL, &tempCharBuffer[0]);
+ tempInfoLog.getLog(static_cast<GLsizei>(tempInfoLog.getLength()), NULL, &tempCharBuffer[0]);
ERR("Error compiling dynamic pixel executable:\n%s\n", &tempCharBuffer[0]);
}
@@ -907,16 +1188,15 @@ gl::Error ProgramD3D::getPixelExecutableForOutputLayout(const std::vector<GLenum
return gl::Error(GL_NO_ERROR);
}
-gl::Error ProgramD3D::getVertexExecutableForInputLayout(const gl::VertexFormat inputLayout[gl::MAX_VERTEX_ATTRIBS],
+gl::Error ProgramD3D::getVertexExecutableForInputLayout(const gl::InputLayout &inputLayout,
ShaderExecutableD3D **outExectuable,
gl::InfoLog *infoLog)
{
- GLenum signature[gl::MAX_VERTEX_ATTRIBS];
- getInputLayoutSignature(inputLayout, signature);
+ VertexExecutable::getSignature(mRenderer, inputLayout, &mCachedVertexSignature);
for (size_t executableIndex = 0; executableIndex < mVertexExecutables.size(); executableIndex++)
{
- if (mVertexExecutables[executableIndex]->matchesSignature(signature))
+ if (mVertexExecutables[executableIndex]->matchesSignature(mCachedVertexSignature))
{
*outExectuable = mVertexExecutables[executableIndex]->shaderExecutable();
return gl::Error(GL_NO_ERROR);
@@ -924,7 +1204,8 @@ gl::Error ProgramD3D::getVertexExecutableForInputLayout(const gl::VertexFormat i
}
// Generate new dynamic layout with attribute conversions
- std::string finalVertexHLSL = mDynamicHLSL->generateVertexShaderForInputLayout(mVertexHLSL, inputLayout, mShaderAttributes);
+ std::string finalVertexHLSL = mDynamicHLSL->generateVertexShaderForInputLayout(
+ mVertexHLSL, inputLayout, mData.getAttributes());
// Generate new vertex executable
ShaderExecutableD3D *vertexExecutable = NULL;
@@ -932,10 +1213,10 @@ gl::Error ProgramD3D::getVertexExecutableForInputLayout(const gl::VertexFormat i
gl::InfoLog tempInfoLog;
gl::InfoLog *currentInfoLog = infoLog ? infoLog : &tempInfoLog;
- gl::Error error = mRenderer->compileToExecutable(*currentInfoLog, finalVertexHLSL, SHADER_VERTEX,
- mTransformFeedbackLinkedVaryings,
- (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS),
- mVertexWorkarounds, &vertexExecutable);
+ gl::Error error = mRenderer->compileToExecutable(
+ *currentInfoLog, finalVertexHLSL, SHADER_VERTEX, mStreamOutVaryings,
+ (mData.getTransformFeedbackBufferMode() == GL_SEPARATE_ATTRIBS), mVertexWorkarounds,
+ &vertexExecutable);
if (error.isError())
{
return error;
@@ -943,12 +1224,13 @@ gl::Error ProgramD3D::getVertexExecutableForInputLayout(const gl::VertexFormat i
if (vertexExecutable)
{
- mVertexExecutables.push_back(new VertexExecutable(inputLayout, signature, vertexExecutable));
+ mVertexExecutables.push_back(
+ new VertexExecutable(inputLayout, mCachedVertexSignature, vertexExecutable));
}
else if (!infoLog)
{
std::vector<char> tempCharBuffer(tempInfoLog.getLength() + 3);
- tempInfoLog.getLog(tempInfoLog.getLength(), NULL, &tempCharBuffer[0]);
+ tempInfoLog.getLog(static_cast<GLsizei>(tempInfoLog.getLength()), NULL, &tempCharBuffer[0]);
ERR("Error compiling dynamic vertex executable:\n%s\n", &tempCharBuffer[0]);
}
@@ -956,50 +1238,96 @@ gl::Error ProgramD3D::getVertexExecutableForInputLayout(const gl::VertexFormat i
return gl::Error(GL_NO_ERROR);
}
-LinkResult ProgramD3D::compileProgramExecutables(gl::InfoLog &infoLog, gl::Shader *fragmentShader, gl::Shader *vertexShader,
- int registers)
+gl::Error ProgramD3D::getGeometryExecutableForPrimitiveType(const gl::Data &data,
+ GLenum drawMode,
+ ShaderExecutableD3D **outExecutable,
+ gl::InfoLog *infoLog)
{
- ShaderD3D *vertexShaderD3D = ShaderD3D::makeShaderD3D(vertexShader->getImplementation());
- ShaderD3D *fragmentShaderD3D = ShaderD3D::makeShaderD3D(fragmentShader->getImplementation());
+ if (outExecutable)
+ {
+ *outExecutable = nullptr;
+ }
+
+ // Return a null shader if the current rendering doesn't use a geometry shader
+ if (!usesGeometryShader(drawMode))
+ {
+ return gl::Error(GL_NO_ERROR);
+ }
+
+ gl::PrimitiveType geometryShaderType = GetGeometryShaderTypeFromDrawMode(drawMode);
+
+ if (mGeometryExecutables[geometryShaderType] != nullptr)
+ {
+ if (outExecutable)
+ {
+ *outExecutable = mGeometryExecutables[geometryShaderType];
+ }
+ return gl::Error(GL_NO_ERROR);
+ }
+
+ std::string geometryHLSL = mDynamicHLSL->generateGeometryShaderHLSL(
+ geometryShaderType, data, mData, mRenderer->presentPathFastEnabled(),
+ mGeometryShaderPreamble);
+
+ gl::InfoLog tempInfoLog;
+ gl::InfoLog *currentInfoLog = infoLog ? infoLog : &tempInfoLog;
+
+ gl::Error error = mRenderer->compileToExecutable(
+ *currentInfoLog, geometryHLSL, SHADER_GEOMETRY, mStreamOutVaryings,
+ (mData.getTransformFeedbackBufferMode() == GL_SEPARATE_ATTRIBS), D3DCompilerWorkarounds(),
+ &mGeometryExecutables[geometryShaderType]);
+
+ if (!infoLog && error.isError())
+ {
+ std::vector<char> tempCharBuffer(tempInfoLog.getLength() + 3);
+ tempInfoLog.getLog(static_cast<GLsizei>(tempInfoLog.getLength()), NULL, &tempCharBuffer[0]);
+ ERR("Error compiling dynamic geometry executable:\n%s\n", &tempCharBuffer[0]);
+ }
+
+ if (outExecutable)
+ {
+ *outExecutable = mGeometryExecutables[geometryShaderType];
+ }
+ return error;
+}
- gl::VertexFormat defaultInputLayout[gl::MAX_VERTEX_ATTRIBS];
- GetDefaultInputLayoutFromShader(vertexShader->getActiveAttributes(), defaultInputLayout);
+LinkResult ProgramD3D::compileProgramExecutables(const gl::Data &data, gl::InfoLog &infoLog)
+{
+ const gl::InputLayout &defaultInputLayout =
+ GetDefaultInputLayoutFromShader(mData.getAttachedVertexShader());
ShaderExecutableD3D *defaultVertexExecutable = NULL;
- gl::Error error = getVertexExecutableForInputLayout(defaultInputLayout, &defaultVertexExecutable, &infoLog);
+ gl::Error error =
+ getVertexExecutableForInputLayout(defaultInputLayout, &defaultVertexExecutable, &infoLog);
if (error.isError())
{
return LinkResult(false, error);
}
- std::vector<GLenum> defaultPixelOutput = GetDefaultOutputLayoutFromShader(getPixelShaderKey());
+ std::vector<GLenum> defaultPixelOutput = GetDefaultOutputLayoutFromShader(getPixelShaderKey());
ShaderExecutableD3D *defaultPixelExecutable = NULL;
- error = getPixelExecutableForOutputLayout(defaultPixelOutput, &defaultPixelExecutable, &infoLog);
+ error =
+ getPixelExecutableForOutputLayout(defaultPixelOutput, &defaultPixelExecutable, &infoLog);
if (error.isError())
{
return LinkResult(false, error);
}
- if (usesGeometryShader())
+ // Auto-generate the geometry shader here, if we expect to be using point rendering in D3D11.
+ ShaderExecutableD3D *pointGS = nullptr;
+ if (usesGeometryShader(GL_POINTS))
{
- std::string geometryHLSL = mDynamicHLSL->generateGeometryShaderHLSL(registers, fragmentShaderD3D, vertexShaderD3D);
-
-
- error = mRenderer->compileToExecutable(infoLog, geometryHLSL, SHADER_GEOMETRY, mTransformFeedbackLinkedVaryings,
- (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS),
- D3DCompilerWorkarounds(), &mGeometryExecutable);
- if (error.isError())
- {
- return LinkResult(false, error);
- }
+ getGeometryExecutableForPrimitiveType(data, GL_POINTS, &pointGS, &infoLog);
}
-#if ANGLE_SHADER_DEBUG_INFO == ANGLE_ENABLED
- if (usesGeometryShader() && mGeometryExecutable)
+ const ShaderD3D *vertexShaderD3D = GetImplAs<ShaderD3D>(mData.getAttachedVertexShader());
+
+ if (usesGeometryShader(GL_POINTS) && pointGS)
{
- // Geometry shaders are currently only used internally, so there is no corresponding shader object at the interface level
- // For now the geometry shader debug info is pre-pended to the vertex shader, this is a bit of a clutch
+ // Geometry shaders are currently only used internally, so there is no corresponding shader
+ // object at the interface level. For now the geometry shader debug info is prepended to
+ // the vertex shader.
vertexShaderD3D->appendDebugInfo("// GEOMETRY SHADER BEGIN\n\n");
- vertexShaderD3D->appendDebugInfo(mGeometryExecutable->getDebugInfo());
+ vertexShaderD3D->appendDebugInfo(pointGS->getDebugInfo());
vertexShaderD3D->appendDebugInfo("\nGEOMETRY SHADER END\n\n\n");
}
@@ -1010,200 +1338,316 @@ LinkResult ProgramD3D::compileProgramExecutables(gl::InfoLog &infoLog, gl::Shade
if (defaultPixelExecutable)
{
+ const ShaderD3D *fragmentShaderD3D =
+ GetImplAs<ShaderD3D>(mData.getAttachedFragmentShader());
fragmentShaderD3D->appendDebugInfo(defaultPixelExecutable->getDebugInfo());
}
-#endif
- bool linkSuccess = (defaultVertexExecutable && defaultPixelExecutable && (!usesGeometryShader() || mGeometryExecutable));
+ bool linkSuccess = (defaultVertexExecutable && defaultPixelExecutable &&
+ (!usesGeometryShader(GL_POINTS) || pointGS));
return LinkResult(linkSuccess, gl::Error(GL_NO_ERROR));
}
-LinkResult ProgramD3D::link(const gl::Data &data, gl::InfoLog &infoLog,
- gl::Shader *fragmentShader, gl::Shader *vertexShader,
- const std::vector<std::string> &transformFeedbackVaryings,
- GLenum transformFeedbackBufferMode,
- int *registers, std::vector<gl::LinkedVarying> *linkedVaryings,
- std::map<int, gl::VariableLocation> *outputVariables)
+LinkResult ProgramD3D::link(const gl::Data &data, gl::InfoLog &infoLog)
{
- ShaderD3D *vertexShaderD3D = ShaderD3D::makeShaderD3D(vertexShader->getImplementation());
- ShaderD3D *fragmentShaderD3D = ShaderD3D::makeShaderD3D(fragmentShader->getImplementation());
+ reset();
- mSamplersPS.resize(data.caps->maxTextureImageUnits);
- mSamplersVS.resize(data.caps->maxVertexTextureImageUnits);
+ // TODO(jmadill): structures containing samplers
+ for (const gl::LinkedUniform &linkedUniform : mData.getUniforms())
+ {
+ if (linkedUniform.isSampler() && linkedUniform.isField())
+ {
+ infoLog << "Structures containing samplers not currently supported in D3D.";
+ return LinkResult(false, gl::Error(GL_NO_ERROR));
+ }
+ }
- mTransformFeedbackBufferMode = transformFeedbackBufferMode;
+ const gl::Shader *vertexShader = mData.getAttachedVertexShader();
+ const gl::Shader *fragmentShader = mData.getAttachedFragmentShader();
- mPixelHLSL = fragmentShaderD3D->getTranslatedSource();
- fragmentShaderD3D->generateWorkarounds(&mPixelWorkarounds);
+ const ShaderD3D *vertexShaderD3D = GetImplAs<ShaderD3D>(vertexShader);
+ const ShaderD3D *fragmentShaderD3D = GetImplAs<ShaderD3D>(fragmentShader);
+
+ mSamplersVS.resize(data.caps->maxVertexTextureImageUnits);
+ mSamplersPS.resize(data.caps->maxTextureImageUnits);
- mVertexHLSL = vertexShaderD3D->getTranslatedSource();
vertexShaderD3D->generateWorkarounds(&mVertexWorkarounds);
- mShaderVersion = vertexShaderD3D->getShaderVersion();
+ fragmentShaderD3D->generateWorkarounds(&mPixelWorkarounds);
+
+ if (mRenderer->getRendererLimitations().noFrontFacingSupport)
+ {
+ if (fragmentShaderD3D->usesFrontFacing())
+ {
+ infoLog << "The current renderer doesn't support gl_FrontFacing";
+ return LinkResult(false, gl::Error(GL_NO_ERROR));
+ }
+ }
+
+ std::vector<PackedVarying> packedVaryings =
+ MergeVaryings(*vertexShader, *fragmentShader, mData.getTransformFeedbackVaryingNames());
// Map the varyings to the register file
- VaryingPacking packing = { NULL };
- *registers = mDynamicHLSL->packVaryings(infoLog, packing, fragmentShaderD3D, vertexShaderD3D, transformFeedbackVaryings);
+ VaryingPacking varyingPacking(data.caps->maxVaryingVectors);
+ if (!varyingPacking.packVaryings(infoLog, packedVaryings,
+ mData.getTransformFeedbackVaryingNames()))
+ {
+ return LinkResult(false, gl::Error(GL_NO_ERROR));
+ }
+
+ ProgramD3DMetadata metadata(mRenderer->getMajorShaderModel(), mRenderer->getShaderModelSuffix(),
+ usesInstancedPointSpriteEmulation(),
+ mRenderer->presentPathFastEnabled(), vertexShaderD3D,
+ fragmentShaderD3D);
- if (*registers < 0)
+ varyingPacking.enableBuiltins(SHADER_VERTEX, metadata);
+ varyingPacking.enableBuiltins(SHADER_PIXEL, metadata);
+
+ if (static_cast<GLuint>(varyingPacking.getRegisterCount()) > data.caps->maxVaryingVectors)
{
+ infoLog << "No varying registers left to support gl_FragCoord/gl_PointCoord";
return LinkResult(false, gl::Error(GL_NO_ERROR));
}
- if (!gl::Program::linkVaryings(infoLog, fragmentShader, vertexShader))
+ // TODO(jmadill): Implement more sophisticated component packing in D3D9.
+ // We can fail here because we use one semantic per GLSL varying. D3D11 can pack varyings
+ // intelligently, but D3D9 assumes one semantic per register.
+ if (mRenderer->getRendererClass() == RENDERER_D3D9 &&
+ varyingPacking.getMaxSemanticIndex() > data.caps->maxVaryingVectors)
{
+ infoLog << "Cannot pack these varyings on D3D9.";
return LinkResult(false, gl::Error(GL_NO_ERROR));
}
- if (!mDynamicHLSL->generateShaderLinkHLSL(data, infoLog, *registers, packing, mPixelHLSL, mVertexHLSL,
- fragmentShaderD3D, vertexShaderD3D, transformFeedbackVaryings,
- linkedVaryings, outputVariables, &mPixelShaderKey, &mUsesFragDepth))
+ if (!mDynamicHLSL->generateShaderLinkHLSL(data, mData, metadata, varyingPacking, &mPixelHLSL,
+ &mVertexHLSL))
{
return LinkResult(false, gl::Error(GL_NO_ERROR));
}
mUsesPointSize = vertexShaderD3D->usesPointSize();
+ mDynamicHLSL->getPixelShaderOutputKey(data, mData, metadata, &mPixelShaderKey);
+ mUsesFragDepth = metadata.usesFragDepth(mData);
- initAttributesByLayout();
+ // Cache if we use flat shading
+ mUsesFlatInterpolation = false;
+ for (const auto &varying : packedVaryings)
+ {
+ if (varying.interpolation == sh::INTERPOLATION_FLAT)
+ {
+ mUsesFlatInterpolation = true;
+ break;
+ }
+ }
+
+ if (mRenderer->getMajorShaderModel() >= 4)
+ {
+ varyingPacking.enableBuiltins(SHADER_GEOMETRY, metadata);
+ mGeometryShaderPreamble = mDynamicHLSL->generateGeometryShaderPreamble(varyingPacking);
+ }
+
+ initSemanticIndex();
+
+ defineUniformsAndAssignRegisters();
+
+ gatherTransformFeedbackVaryings(varyingPacking);
+
+ LinkResult result = compileProgramExecutables(data, infoLog);
+ if (result.error.isError() || !result.linkSuccess)
+ {
+ infoLog << "Failed to create D3D shaders.";
+ return result;
+ }
+
+ initUniformBlockInfo();
return LinkResult(true, gl::Error(GL_NO_ERROR));
}
-void ProgramD3D::getInputLayoutSignature(const gl::VertexFormat inputLayout[], GLenum signature[]) const
+GLboolean ProgramD3D::validate(const gl::Caps & /*caps*/, gl::InfoLog * /*infoLog*/)
{
- mDynamicHLSL->getInputLayoutSignature(inputLayout, signature);
+ // TODO(jmadill): Do something useful here?
+ return GL_TRUE;
+}
+
+void ProgramD3D::initUniformBlockInfo()
+{
+ const gl::Shader *vertexShader = mData.getAttachedVertexShader();
+
+ for (const sh::InterfaceBlock &vertexBlock : vertexShader->getInterfaceBlocks())
+ {
+ if (!vertexBlock.staticUse && vertexBlock.layout == sh::BLOCKLAYOUT_PACKED)
+ continue;
+
+ if (mBlockDataSizes.count(vertexBlock.name) > 0)
+ continue;
+
+ size_t dataSize = getUniformBlockInfo(vertexBlock);
+ mBlockDataSizes[vertexBlock.name] = dataSize;
+ }
+
+ const gl::Shader *fragmentShader = mData.getAttachedFragmentShader();
+
+ for (const sh::InterfaceBlock &fragmentBlock : fragmentShader->getInterfaceBlocks())
+ {
+ if (!fragmentBlock.staticUse && fragmentBlock.layout == sh::BLOCKLAYOUT_PACKED)
+ continue;
+
+ if (mBlockDataSizes.count(fragmentBlock.name) > 0)
+ continue;
+
+ size_t dataSize = getUniformBlockInfo(fragmentBlock);
+ mBlockDataSizes[fragmentBlock.name] = dataSize;
+ }
+}
+
+void ProgramD3D::assignUniformBlockRegisters()
+{
+ mD3DUniformBlocks.clear();
+
+ // Assign registers and update sizes.
+ const ShaderD3D *vertexShaderD3D = GetImplAs<ShaderD3D>(mData.getAttachedVertexShader());
+ const ShaderD3D *fragmentShaderD3D = GetImplAs<ShaderD3D>(mData.getAttachedFragmentShader());
+
+ for (const gl::UniformBlock &uniformBlock : mData.getUniformBlocks())
+ {
+ unsigned int uniformBlockElement = uniformBlock.isArray ? uniformBlock.arrayElement : 0;
+
+ D3DUniformBlock d3dUniformBlock;
+
+ if (uniformBlock.vertexStaticUse)
+ {
+ unsigned int baseRegister =
+ vertexShaderD3D->getInterfaceBlockRegister(uniformBlock.name);
+ d3dUniformBlock.vsRegisterIndex = baseRegister + uniformBlockElement;
+ }
+
+ if (uniformBlock.fragmentStaticUse)
+ {
+ unsigned int baseRegister =
+ fragmentShaderD3D->getInterfaceBlockRegister(uniformBlock.name);
+ d3dUniformBlock.psRegisterIndex = baseRegister + uniformBlockElement;
+ }
+
+ mD3DUniformBlocks.push_back(d3dUniformBlock);
+ }
}
void ProgramD3D::initializeUniformStorage()
{
// Compute total default block size
- unsigned int vertexRegisters = 0;
+ unsigned int vertexRegisters = 0;
unsigned int fragmentRegisters = 0;
- for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
+ for (const D3DUniform *d3dUniform : mD3DUniforms)
{
- const gl::LinkedUniform &uniform = *mUniforms[uniformIndex];
-
- if (!gl::IsSamplerType(uniform.type))
+ if (!d3dUniform->isSampler())
{
- if (uniform.isReferencedByVertexShader())
+ if (d3dUniform->isReferencedByVertexShader())
{
- vertexRegisters = std::max(vertexRegisters, uniform.vsRegisterIndex + uniform.registerCount);
+ vertexRegisters = std::max(vertexRegisters,
+ d3dUniform->vsRegisterIndex + d3dUniform->registerCount);
}
- if (uniform.isReferencedByFragmentShader())
+ if (d3dUniform->isReferencedByFragmentShader())
{
- fragmentRegisters = std::max(fragmentRegisters, uniform.psRegisterIndex + uniform.registerCount);
+ fragmentRegisters = std::max(
+ fragmentRegisters, d3dUniform->psRegisterIndex + d3dUniform->registerCount);
}
}
}
- mVertexUniformStorage = mRenderer->createUniformStorage(vertexRegisters * 16u);
+ mVertexUniformStorage = mRenderer->createUniformStorage(vertexRegisters * 16u);
mFragmentUniformStorage = mRenderer->createUniformStorage(fragmentRegisters * 16u);
}
-gl::Error ProgramD3D::applyUniforms()
+gl::Error ProgramD3D::applyUniforms(GLenum drawMode)
{
- updateSamplerMapping();
+ ASSERT(!mDirtySamplerMapping);
- gl::Error error = mRenderer->applyUniforms(*this, mUniforms);
+ gl::Error error = mRenderer->applyUniforms(*this, drawMode, mD3DUniforms);
if (error.isError())
{
return error;
}
- for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
+ for (D3DUniform *d3dUniform : mD3DUniforms)
{
- mUniforms[uniformIndex]->dirty = false;
+ d3dUniform->dirty = false;
}
return gl::Error(GL_NO_ERROR);
}
-gl::Error ProgramD3D::applyUniformBuffers(const gl::Data &data, GLuint uniformBlockBindings[])
+gl::Error ProgramD3D::applyUniformBuffers(const gl::Data &data)
{
- GLint vertexUniformBuffers[gl::IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS];
- GLint fragmentUniformBuffers[gl::IMPLEMENTATION_MAX_FRAGMENT_SHADER_UNIFORM_BUFFERS];
-
- for (unsigned int registerIndex = 0; registerIndex < gl::IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS; ++registerIndex)
+ if (mData.getUniformBlocks().empty())
{
- vertexUniformBuffers[registerIndex] = -1;
+ return gl::Error(GL_NO_ERROR);
}
- for (unsigned int registerIndex = 0; registerIndex < gl::IMPLEMENTATION_MAX_FRAGMENT_SHADER_UNIFORM_BUFFERS; ++registerIndex)
+ // Lazy init.
+ if (mD3DUniformBlocks.empty())
{
- fragmentUniformBuffers[registerIndex] = -1;
+ assignUniformBlockRegisters();
}
+ mVertexUBOCache.clear();
+ mFragmentUBOCache.clear();
+
const unsigned int reservedBuffersInVS = mRenderer->getReservedVertexUniformBuffers();
const unsigned int reservedBuffersInFS = mRenderer->getReservedFragmentUniformBuffers();
- for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < mUniformBlocks.size(); uniformBlockIndex++)
+ for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < mD3DUniformBlocks.size();
+ uniformBlockIndex++)
{
- gl::UniformBlock *uniformBlock = mUniformBlocks[uniformBlockIndex];
- GLuint blockBinding = uniformBlockBindings[uniformBlockIndex];
-
- ASSERT(uniformBlock);
+ const D3DUniformBlock &uniformBlock = mD3DUniformBlocks[uniformBlockIndex];
+ GLuint blockBinding = mData.getUniformBlockBinding(uniformBlockIndex);
// Unnecessary to apply an unreferenced standard or shared UBO
- if (!uniformBlock->isReferencedByVertexShader() && !uniformBlock->isReferencedByFragmentShader())
+ if (!uniformBlock.vertexStaticUse() && !uniformBlock.fragmentStaticUse())
{
continue;
}
- if (uniformBlock->isReferencedByVertexShader())
+ if (uniformBlock.vertexStaticUse())
{
- unsigned int registerIndex = uniformBlock->vsRegisterIndex - reservedBuffersInVS;
- ASSERT(vertexUniformBuffers[registerIndex] == -1);
+ unsigned int registerIndex = uniformBlock.vsRegisterIndex - reservedBuffersInVS;
ASSERT(registerIndex < data.caps->maxVertexUniformBlocks);
- vertexUniformBuffers[registerIndex] = blockBinding;
+
+ if (mVertexUBOCache.size() <= registerIndex)
+ {
+ mVertexUBOCache.resize(registerIndex + 1, -1);
+ }
+
+ ASSERT(mVertexUBOCache[registerIndex] == -1);
+ mVertexUBOCache[registerIndex] = blockBinding;
}
- if (uniformBlock->isReferencedByFragmentShader())
+ if (uniformBlock.fragmentStaticUse())
{
- unsigned int registerIndex = uniformBlock->psRegisterIndex - reservedBuffersInFS;
- ASSERT(fragmentUniformBuffers[registerIndex] == -1);
+ unsigned int registerIndex = uniformBlock.psRegisterIndex - reservedBuffersInFS;
ASSERT(registerIndex < data.caps->maxFragmentUniformBlocks);
- fragmentUniformBuffers[registerIndex] = blockBinding;
- }
- }
- return mRenderer->setUniformBuffers(data, vertexUniformBuffers, fragmentUniformBuffers);
-}
+ if (mFragmentUBOCache.size() <= registerIndex)
+ {
+ mFragmentUBOCache.resize(registerIndex + 1, -1);
+ }
-bool ProgramD3D::assignUniformBlockRegister(gl::InfoLog &infoLog, gl::UniformBlock *uniformBlock, GLenum shader,
- unsigned int registerIndex, const gl::Caps &caps)
-{
- if (shader == GL_VERTEX_SHADER)
- {
- uniformBlock->vsRegisterIndex = registerIndex;
- if (registerIndex - mRenderer->getReservedVertexUniformBuffers() >= caps.maxVertexUniformBlocks)
- {
- infoLog.append("Vertex shader uniform block count exceed GL_MAX_VERTEX_UNIFORM_BLOCKS (%u)", caps.maxVertexUniformBlocks);
- return false;
+ ASSERT(mFragmentUBOCache[registerIndex] == -1);
+ mFragmentUBOCache[registerIndex] = blockBinding;
}
}
- else if (shader == GL_FRAGMENT_SHADER)
- {
- uniformBlock->psRegisterIndex = registerIndex;
- if (registerIndex - mRenderer->getReservedFragmentUniformBuffers() >= caps.maxFragmentUniformBlocks)
- {
- infoLog.append("Fragment shader uniform block count exceed GL_MAX_FRAGMENT_UNIFORM_BLOCKS (%u)", caps.maxFragmentUniformBlocks);
- return false;
- }
- }
- else UNREACHABLE();
- return true;
+ return mRenderer->setUniformBuffers(data, mVertexUBOCache, mFragmentUBOCache);
}
void ProgramD3D::dirtyAllUniforms()
{
- unsigned int numUniforms = mUniforms.size();
- for (unsigned int index = 0; index < numUniforms; index++)
+ for (D3DUniform *d3dUniform : mD3DUniforms)
{
- mUniforms[index]->dirty = true;
+ d3dUniform->dirty = true;
}
}
-void ProgramD3D::setUniform1fv(GLint location, GLsizei count, const GLfloat* v)
+void ProgramD3D::setUniform1fv(GLint location, GLsizei count, const GLfloat *v)
{
setUniform(location, count, v, GL_FLOAT);
}
@@ -1223,47 +1667,74 @@ void ProgramD3D::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
setUniform(location, count, v, GL_FLOAT_VEC4);
}
-void ProgramD3D::setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
+void ProgramD3D::setUniformMatrix2fv(GLint location,
+ GLsizei count,
+ GLboolean transpose,
+ const GLfloat *value)
{
setUniformMatrixfv<2, 2>(location, count, transpose, value, GL_FLOAT_MAT2);
}
-void ProgramD3D::setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
+void ProgramD3D::setUniformMatrix3fv(GLint location,
+ GLsizei count,
+ GLboolean transpose,
+ const GLfloat *value)
{
setUniformMatrixfv<3, 3>(location, count, transpose, value, GL_FLOAT_MAT3);
}
-void ProgramD3D::setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
+void ProgramD3D::setUniformMatrix4fv(GLint location,
+ GLsizei count,
+ GLboolean transpose,
+ const GLfloat *value)
{
setUniformMatrixfv<4, 4>(location, count, transpose, value, GL_FLOAT_MAT4);
}
-void ProgramD3D::setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
+void ProgramD3D::setUniformMatrix2x3fv(GLint location,
+ GLsizei count,
+ GLboolean transpose,
+ const GLfloat *value)
{
setUniformMatrixfv<2, 3>(location, count, transpose, value, GL_FLOAT_MAT2x3);
}
-void ProgramD3D::setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
+void ProgramD3D::setUniformMatrix3x2fv(GLint location,
+ GLsizei count,
+ GLboolean transpose,
+ const GLfloat *value)
{
setUniformMatrixfv<3, 2>(location, count, transpose, value, GL_FLOAT_MAT3x2);
}
-void ProgramD3D::setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
+void ProgramD3D::setUniformMatrix2x4fv(GLint location,
+ GLsizei count,
+ GLboolean transpose,
+ const GLfloat *value)
{
setUniformMatrixfv<2, 4>(location, count, transpose, value, GL_FLOAT_MAT2x4);
}
-void ProgramD3D::setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
+void ProgramD3D::setUniformMatrix4x2fv(GLint location,
+ GLsizei count,
+ GLboolean transpose,
+ const GLfloat *value)
{
setUniformMatrixfv<4, 2>(location, count, transpose, value, GL_FLOAT_MAT4x2);
}
-void ProgramD3D::setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
+void ProgramD3D::setUniformMatrix3x4fv(GLint location,
+ GLsizei count,
+ GLboolean transpose,
+ const GLfloat *value)
{
setUniformMatrixfv<3, 4>(location, count, transpose, value, GL_FLOAT_MAT3x4);
}
-void ProgramD3D::setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
+void ProgramD3D::setUniformMatrix4x3fv(GLint location,
+ GLsizei count,
+ GLboolean transpose,
+ const GLfloat *value)
{
setUniformMatrixfv<4, 3>(location, count, transpose, value, GL_FLOAT_MAT4x3);
}
@@ -1308,106 +1779,86 @@ void ProgramD3D::setUniform4uiv(GLint location, GLsizei count, const GLuint *v)
setUniform(location, count, v, GL_UNSIGNED_INT_VEC4);
}
-void ProgramD3D::getUniformfv(GLint location, GLfloat *params)
+void ProgramD3D::setUniformBlockBinding(GLuint /*uniformBlockIndex*/,
+ GLuint /*uniformBlockBinding*/)
{
- getUniformv(location, params, GL_FLOAT);
}
-void ProgramD3D::getUniformiv(GLint location, GLint *params)
+void ProgramD3D::defineUniformsAndAssignRegisters()
{
- getUniformv(location, params, GL_INT);
-}
-
-void ProgramD3D::getUniformuiv(GLint location, GLuint *params)
-{
- getUniformv(location, params, GL_UNSIGNED_INT);
-}
+ D3DUniformMap uniformMap;
+ const gl::Shader *vertexShader = mData.getAttachedVertexShader();
+ for (const sh::Uniform &vertexUniform : vertexShader->getUniforms())
-bool ProgramD3D::linkUniforms(gl::InfoLog &infoLog, const gl::Shader &vertexShader, const gl::Shader &fragmentShader,
- const gl::Caps &caps)
-{
- const ShaderD3D *vertexShaderD3D = ShaderD3D::makeShaderD3D(vertexShader.getImplementation());
- const ShaderD3D *fragmentShaderD3D = ShaderD3D::makeShaderD3D(fragmentShader.getImplementation());
-
- const std::vector<sh::Uniform> &vertexUniforms = vertexShader.getUniforms();
- const std::vector<sh::Uniform> &fragmentUniforms = fragmentShader.getUniforms();
-
- // Check that uniforms defined in the vertex and fragment shaders are identical
- typedef std::map<std::string, const sh::Uniform*> UniformMap;
- UniformMap linkedUniforms;
-
- for (unsigned int vertexUniformIndex = 0; vertexUniformIndex < vertexUniforms.size(); vertexUniformIndex++)
{
- const sh::Uniform &vertexUniform = vertexUniforms[vertexUniformIndex];
- linkedUniforms[vertexUniform.name] = &vertexUniform;
- }
-
- for (unsigned int fragmentUniformIndex = 0; fragmentUniformIndex < fragmentUniforms.size(); fragmentUniformIndex++)
- {
- const sh::Uniform &fragmentUniform = fragmentUniforms[fragmentUniformIndex];
- UniformMap::const_iterator entry = linkedUniforms.find(fragmentUniform.name);
- if (entry != linkedUniforms.end())
+ if (vertexUniform.staticUse)
{
- const sh::Uniform &vertexUniform = *entry->second;
- const std::string &uniformName = "uniform '" + vertexUniform.name + "'";
- if (!gl::Program::linkValidateUniforms(infoLog, uniformName, vertexUniform, fragmentUniform))
- {
- return false;
- }
+ defineUniformBase(vertexShader, vertexUniform, &uniformMap);
}
}
- for (unsigned int uniformIndex = 0; uniformIndex < vertexUniforms.size(); uniformIndex++)
+ const gl::Shader *fragmentShader = mData.getAttachedFragmentShader();
+ for (const sh::Uniform &fragmentUniform : fragmentShader->getUniforms())
{
- const sh::Uniform &uniform = vertexUniforms[uniformIndex];
-
- if (uniform.staticUse)
+ if (fragmentUniform.staticUse)
{
- defineUniformBase(vertexShaderD3D, uniform, vertexShaderD3D->getUniformRegister(uniform.name));
+ defineUniformBase(fragmentShader, fragmentUniform, &uniformMap);
}
}
- for (unsigned int uniformIndex = 0; uniformIndex < fragmentUniforms.size(); uniformIndex++)
+ // Initialize the D3DUniform list to mirror the indexing of the GL layer.
+ for (const gl::LinkedUniform &glUniform : mData.getUniforms())
{
- const sh::Uniform &uniform = fragmentUniforms[uniformIndex];
-
- if (uniform.staticUse)
- {
- defineUniformBase(fragmentShaderD3D, uniform, fragmentShaderD3D->getUniformRegister(uniform.name));
- }
- }
+ if (!glUniform.isInDefaultBlock())
+ continue;
- if (!indexUniforms(infoLog, caps))
- {
- return false;
+ auto mapEntry = uniformMap.find(glUniform.name);
+ ASSERT(mapEntry != uniformMap.end());
+ mD3DUniforms.push_back(mapEntry->second);
}
+ assignAllSamplerRegisters();
initializeUniformStorage();
+}
- // special case for gl_DepthRange, the only built-in uniform (also a struct)
- if (vertexShaderD3D->usesDepthRange() || fragmentShaderD3D->usesDepthRange())
+void ProgramD3D::defineUniformBase(const gl::Shader *shader,
+ const sh::Uniform &uniform,
+ D3DUniformMap *uniformMap)
+{
+ if (uniform.isBuiltIn())
{
- const sh::BlockMemberInfo &defaultInfo = sh::BlockMemberInfo::getDefaultBlockInfo();
-
- mUniforms.push_back(new gl::LinkedUniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.near", 0, -1, defaultInfo));
- mUniforms.push_back(new gl::LinkedUniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.far", 0, -1, defaultInfo));
- mUniforms.push_back(new gl::LinkedUniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.diff", 0, -1, defaultInfo));
+ defineUniform(shader->getType(), uniform, uniform.name, nullptr, uniformMap);
+ return;
}
- return true;
+ const ShaderD3D *shaderD3D = GetImplAs<ShaderD3D>(shader);
+
+ unsigned int startRegister = shaderD3D->getUniformRegister(uniform.name);
+ ShShaderOutput outputType = shaderD3D->getCompilerOutputType();
+ sh::HLSLBlockEncoder encoder(sh::HLSLBlockEncoder::GetStrategyFor(outputType));
+ encoder.skipRegisters(startRegister);
+
+ defineUniform(shader->getType(), uniform, uniform.name, &encoder, uniformMap);
}
-void ProgramD3D::defineUniformBase(const ShaderD3D *shader, const sh::Uniform &uniform, unsigned int uniformRegister)
+D3DUniform *ProgramD3D::getD3DUniformByName(const std::string &name)
{
- ShShaderOutput outputType = shader->getCompilerOutputType();
- sh::HLSLBlockEncoder encoder(sh::HLSLBlockEncoder::GetStrategyFor(outputType));
- encoder.skipRegisters(uniformRegister);
+ for (D3DUniform *d3dUniform : mD3DUniforms)
+ {
+ if (d3dUniform->name == name)
+ {
+ return d3dUniform;
+ }
+ }
- defineUniform(shader, uniform, uniform.name, &encoder);
+ return nullptr;
}
-void ProgramD3D::defineUniform(const ShaderD3D *shader, const sh::ShaderVariable &uniform,
- const std::string &fullName, sh::HLSLBlockEncoder *encoder)
+void ProgramD3D::defineUniform(GLenum shaderType,
+ const sh::ShaderVariable &uniform,
+ const std::string &fullName,
+ sh::HLSLBlockEncoder *encoder,
+ D3DUniformMap *uniformMap)
{
if (uniform.isStruct())
{
@@ -1415,50 +1866,62 @@ void ProgramD3D::defineUniform(const ShaderD3D *shader, const sh::ShaderVariable
{
const std::string &elementString = (uniform.isArray() ? ArrayString(elementIndex) : "");
- encoder->enterAggregateType();
+ if (encoder)
+ encoder->enterAggregateType();
for (size_t fieldIndex = 0; fieldIndex < uniform.fields.size(); fieldIndex++)
{
- const sh::ShaderVariable &field = uniform.fields[fieldIndex];
+ const sh::ShaderVariable &field = uniform.fields[fieldIndex];
const std::string &fieldFullName = (fullName + elementString + "." + field.name);
- defineUniform(shader, field, fieldFullName, encoder);
+ defineUniform(shaderType, field, fieldFullName, encoder, uniformMap);
}
- encoder->exitAggregateType();
+ if (encoder)
+ encoder->exitAggregateType();
}
+ return;
}
- else // Not a struct
+
+ // Not a struct. Arrays are treated as aggregate types.
+ if (uniform.isArray() && encoder)
{
- // Arrays are treated as aggregate types
- if (uniform.isArray())
- {
- encoder->enterAggregateType();
- }
+ encoder->enterAggregateType();
+ }
- gl::LinkedUniform *linkedUniform = getUniformByName(fullName);
+ // Advance the uniform offset, to track registers allocation for structs
+ sh::BlockMemberInfo blockInfo =
+ encoder ? encoder->encodeType(uniform.type, uniform.arraySize, false)
+ : sh::BlockMemberInfo::getDefaultBlockInfo();
- // Advance the uniform offset, to track registers allocation for structs
- sh::BlockMemberInfo blockInfo = encoder->encodeType(uniform.type, uniform.arraySize, false);
+ auto uniformMapEntry = uniformMap->find(fullName);
+ D3DUniform *d3dUniform = nullptr;
- if (!linkedUniform)
- {
- linkedUniform = new gl::LinkedUniform(uniform.type, uniform.precision, fullName, uniform.arraySize,
- -1, sh::BlockMemberInfo::getDefaultBlockInfo());
- ASSERT(linkedUniform);
- linkedUniform->registerElement = sh::HLSLBlockEncoder::getBlockRegisterElement(blockInfo);
- mUniforms.push_back(linkedUniform);
- }
+ if (uniformMapEntry != uniformMap->end())
+ {
+ d3dUniform = uniformMapEntry->second;
+ }
+ else
+ {
+ d3dUniform = new D3DUniform(uniform.type, fullName, uniform.arraySize, true);
+ (*uniformMap)[fullName] = d3dUniform;
+ }
- if (shader->getShaderType() == GL_FRAGMENT_SHADER)
+ if (encoder)
+ {
+ d3dUniform->registerElement =
+ static_cast<unsigned int>(sh::HLSLBlockEncoder::getBlockRegisterElement(blockInfo));
+ unsigned int reg =
+ static_cast<unsigned int>(sh::HLSLBlockEncoder::getBlockRegister(blockInfo));
+ if (shaderType == GL_FRAGMENT_SHADER)
{
- linkedUniform->psRegisterIndex = sh::HLSLBlockEncoder::getBlockRegister(blockInfo);
+ d3dUniform->psRegisterIndex = reg;
}
- else if (shader->getShaderType() == GL_VERTEX_SHADER)
+ else
{
- linkedUniform->vsRegisterIndex = sh::HLSLBlockEncoder::getBlockRegister(blockInfo);
+ ASSERT(shaderType == GL_VERTEX_SHADER);
+ d3dUniform->vsRegisterIndex = reg;
}
- else UNREACHABLE();
// Arrays are treated as aggregate types
if (uniform.isArray())
@@ -1469,34 +1932,24 @@ void ProgramD3D::defineUniform(const ShaderD3D *shader, const sh::ShaderVariable
}
template <typename T>
-static inline void SetIfDirty(T *dest, const T& source, bool *dirtyFlag)
-{
- ASSERT(dest != NULL);
- ASSERT(dirtyFlag != NULL);
-
- *dirtyFlag = *dirtyFlag || (memcmp(dest, &source, sizeof(T)) != 0);
- *dest = source;
-}
-
-template <typename T>
-void ProgramD3D::setUniform(GLint location, GLsizei count, const T* v, GLenum targetUniformType)
+void ProgramD3D::setUniform(GLint location, GLsizei countIn, const T *v, GLenum targetUniformType)
{
- const int components = gl::VariableComponentCount(targetUniformType);
+ const int components = gl::VariableComponentCount(targetUniformType);
const GLenum targetBoolType = gl::VariableBoolVectorType(targetUniformType);
- gl::LinkedUniform *targetUniform = getUniformByLocation(location);
+ D3DUniform *targetUniform = getD3DUniformFromLocation(location);
- int elementCount = targetUniform->elementCount();
-
- count = std::min(elementCount - (int)mUniformIndex[location].element, count);
+ unsigned int elementCount = targetUniform->elementCount();
+ unsigned int arrayElement = mData.getUniformLocations()[location].element;
+ unsigned int count = std::min(elementCount - arrayElement, static_cast<unsigned int>(countIn));
if (targetUniform->type == targetUniformType)
{
- T *target = reinterpret_cast<T*>(targetUniform->data) + mUniformIndex[location].element * 4;
+ T *target = reinterpret_cast<T *>(targetUniform->data) + arrayElement * 4;
- for (int i = 0; i < count; i++)
+ for (unsigned int i = 0; i < count; i++)
{
- T *dest = target + (i * 4);
+ T *dest = target + (i * 4);
const T *source = v + (i * components);
for (int c = 0; c < components; c++)
@@ -1511,16 +1964,17 @@ void ProgramD3D::setUniform(GLint location, GLsizei count, const T* v, GLenum ta
}
else if (targetUniform->type == targetBoolType)
{
- GLint *boolParams = reinterpret_cast<GLint*>(targetUniform->data) + mUniformIndex[location].element * 4;
+ GLint *boolParams = reinterpret_cast<GLint *>(targetUniform->data) + arrayElement * 4;
- for (int i = 0; i < count; i++)
+ for (unsigned int i = 0; i < count; i++)
{
- GLint *dest = boolParams + (i * 4);
+ GLint *dest = boolParams + (i * 4);
const T *source = v + (i * components);
for (int c = 0; c < components; c++)
{
- SetIfDirty(dest + c, (source[c] == static_cast<T>(0)) ? GL_FALSE : GL_TRUE, &targetUniform->dirty);
+ SetIfDirty(dest + c, (source[c] == static_cast<T>(0)) ? GL_FALSE : GL_TRUE,
+ &targetUniform->dirty);
}
for (int c = components; c < 4; c++)
{
@@ -1528,18 +1982,18 @@ void ProgramD3D::setUniform(GLint location, GLsizei count, const T* v, GLenum ta
}
}
}
- else if (gl::IsSamplerType(targetUniform->type))
+ else if (targetUniform->isSampler())
{
ASSERT(targetUniformType == GL_INT);
- GLint *target = reinterpret_cast<GLint*>(targetUniform->data) + mUniformIndex[location].element * 4;
+ GLint *target = reinterpret_cast<GLint *>(targetUniform->data) + arrayElement * 4;
bool wasDirty = targetUniform->dirty;
- for (int i = 0; i < count; i++)
+ for (unsigned int i = 0; i < count; i++)
{
- GLint *dest = target + (i * 4);
- const GLint *source = reinterpret_cast<const GLint*>(v) + (i * components);
+ GLint *dest = target + (i * 4);
+ const GLint *source = reinterpret_cast<const GLint *>(v) + (i * components);
SetIfDirty(dest + 0, source[0], &targetUniform->dirty);
SetIfDirty(dest + 1, 0, &targetUniform->dirty);
@@ -1552,404 +2006,142 @@ void ProgramD3D::setUniform(GLint location, GLsizei count, const T* v, GLenum ta
mDirtySamplerMapping = true;
}
}
- else UNREACHABLE();
-}
-
-template<typename T>
-bool transposeMatrix(T *target, const GLfloat *value, int targetWidth, int targetHeight, int srcWidth, int srcHeight)
-{
- bool dirty = false;
- int copyWidth = std::min(targetHeight, srcWidth);
- int copyHeight = std::min(targetWidth, srcHeight);
-
- for (int x = 0; x < copyWidth; x++)
- {
- for (int y = 0; y < copyHeight; y++)
- {
- SetIfDirty(target + (x * targetWidth + y), static_cast<T>(value[y * srcWidth + x]), &dirty);
- }
- }
- // clear unfilled right side
- for (int y = 0; y < copyWidth; y++)
- {
- for (int x = copyHeight; x < targetWidth; x++)
- {
- SetIfDirty(target + (y * targetWidth + x), static_cast<T>(0), &dirty);
- }
- }
- // clear unfilled bottom.
- for (int y = copyWidth; y < targetHeight; y++)
- {
- for (int x = 0; x < targetWidth; x++)
- {
- SetIfDirty(target + (y * targetWidth + x), static_cast<T>(0), &dirty);
- }
- }
-
- return dirty;
-}
-
-template<typename T>
-bool expandMatrix(T *target, const GLfloat *value, int targetWidth, int targetHeight, int srcWidth, int srcHeight)
-{
- bool dirty = false;
- int copyWidth = std::min(targetWidth, srcWidth);
- int copyHeight = std::min(targetHeight, srcHeight);
-
- for (int y = 0; y < copyHeight; y++)
- {
- for (int x = 0; x < copyWidth; x++)
- {
- SetIfDirty(target + (y * targetWidth + x), static_cast<T>(value[y * srcWidth + x]), &dirty);
- }
- }
- // clear unfilled right side
- for (int y = 0; y < copyHeight; y++)
- {
- for (int x = copyWidth; x < targetWidth; x++)
- {
- SetIfDirty(target + (y * targetWidth + x), static_cast<T>(0), &dirty);
- }
- }
- // clear unfilled bottom.
- for (int y = copyHeight; y < targetHeight; y++)
- {
- for (int x = 0; x < targetWidth; x++)
- {
- SetIfDirty(target + (y * targetWidth + x), static_cast<T>(0), &dirty);
- }
- }
-
- return dirty;
+ else
+ UNREACHABLE();
}
template <int cols, int rows>
-void ProgramD3D::setUniformMatrixfv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value, GLenum targetUniformType)
+void ProgramD3D::setUniformMatrixfv(GLint location,
+ GLsizei countIn,
+ GLboolean transpose,
+ const GLfloat *value,
+ GLenum targetUniformType)
{
- gl::LinkedUniform *targetUniform = getUniformByLocation(location);
+ D3DUniform *targetUniform = getD3DUniformFromLocation(location);
- int elementCount = targetUniform->elementCount();
+ unsigned int elementCount = targetUniform->elementCount();
+ unsigned int arrayElement = mData.getUniformLocations()[location].element;
+ unsigned int count = std::min(elementCount - arrayElement, static_cast<unsigned int>(countIn));
- count = std::min(elementCount - (int)mUniformIndex[location].element, count);
const unsigned int targetMatrixStride = (4 * rows);
- GLfloat *target = (GLfloat*)(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * targetMatrixStride);
+ GLfloat *target =
+ (GLfloat *)(targetUniform->data + arrayElement * sizeof(GLfloat) * targetMatrixStride);
- for (int i = 0; i < count; i++)
+ for (unsigned int i = 0; i < count; i++)
{
// Internally store matrices as transposed versions to accomodate HLSL matrix indexing
if (transpose == GL_FALSE)
{
- targetUniform->dirty = transposeMatrix<GLfloat>(target, value, 4, rows, rows, cols) || targetUniform->dirty;
+ targetUniform->dirty = TransposeMatrix<GLfloat>(target, value, 4, rows, rows, cols) ||
+ targetUniform->dirty;
}
else
{
- targetUniform->dirty = expandMatrix<GLfloat>(target, value, 4, rows, cols, rows) || targetUniform->dirty;
+ targetUniform->dirty =
+ ExpandMatrix<GLfloat>(target, value, 4, rows, cols, rows) || targetUniform->dirty;
}
target += targetMatrixStride;
value += cols * rows;
}
}
-template <typename T>
-void ProgramD3D::getUniformv(GLint location, T *params, GLenum uniformType)
+size_t ProgramD3D::getUniformBlockInfo(const sh::InterfaceBlock &interfaceBlock)
{
- gl::LinkedUniform *targetUniform = mUniforms[mUniformIndex[location].index];
+ ASSERT(interfaceBlock.staticUse || interfaceBlock.layout != sh::BLOCKLAYOUT_PACKED);
- if (gl::IsMatrixType(targetUniform->type))
- {
- const int rows = gl::VariableRowCount(targetUniform->type);
- const int cols = gl::VariableColumnCount(targetUniform->type);
- transposeMatrix(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4 * rows, rows, cols, 4, rows);
- }
- else if (uniformType == gl::VariableComponentType(targetUniform->type))
+ // define member uniforms
+ sh::Std140BlockEncoder std140Encoder;
+ sh::HLSLBlockEncoder hlslEncoder(sh::HLSLBlockEncoder::ENCODE_PACKED);
+ sh::BlockLayoutEncoder *encoder = nullptr;
+
+ if (interfaceBlock.layout == sh::BLOCKLAYOUT_STANDARD)
{
- unsigned int size = gl::VariableComponentCount(targetUniform->type);
- memcpy(params, targetUniform->data + mUniformIndex[location].element * 4 * sizeof(T),
- size * sizeof(T));
+ encoder = &std140Encoder;
}
else
{
- unsigned int size = gl::VariableComponentCount(targetUniform->type);
- switch (gl::VariableComponentType(targetUniform->type))
- {
- case GL_BOOL:
- {
- GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
-
- for (unsigned int i = 0; i < size; i++)
- {
- params[i] = (boolParams[i] == GL_FALSE) ? static_cast<T>(0) : static_cast<T>(1);
- }
- }
- break;
-
- case GL_FLOAT:
- {
- GLfloat *floatParams = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
-
- for (unsigned int i = 0; i < size; i++)
- {
- params[i] = static_cast<T>(floatParams[i]);
- }
- }
- break;
-
- case GL_INT:
- {
- GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
-
- for (unsigned int i = 0; i < size; i++)
- {
- params[i] = static_cast<T>(intParams[i]);
- }
- }
- break;
+ encoder = &hlslEncoder;
+ }
- case GL_UNSIGNED_INT:
- {
- GLuint *uintParams = (GLuint*)targetUniform->data + mUniformIndex[location].element * 4;
+ GetUniformBlockInfo(interfaceBlock.fields, interfaceBlock.fieldPrefix(), encoder,
+ interfaceBlock.isRowMajorLayout, &mBlockInfo);
- for (unsigned int i = 0; i < size; i++)
- {
- params[i] = static_cast<T>(uintParams[i]);
- }
- }
- break;
-
- default: UNREACHABLE();
- }
- }
+ return encoder->getBlockSize();
}
-template <typename VarT>
-void ProgramD3D::defineUniformBlockMembers(const std::vector<VarT> &fields, const std::string &prefix, int blockIndex,
- sh::BlockLayoutEncoder *encoder, std::vector<unsigned int> *blockUniformIndexes,
- bool inRowMajorLayout)
+void ProgramD3D::assignAllSamplerRegisters()
{
- for (unsigned int uniformIndex = 0; uniformIndex < fields.size(); uniformIndex++)
+ for (const D3DUniform *d3dUniform : mD3DUniforms)
{
- const VarT &field = fields[uniformIndex];
- const std::string &fieldName = (prefix.empty() ? field.name : prefix + "." + field.name);
-
- if (field.isStruct())
- {
- bool rowMajorLayout = (inRowMajorLayout || IsRowMajorLayout(field));
-
- for (unsigned int arrayElement = 0; arrayElement < field.elementCount(); arrayElement++)
- {
- encoder->enterAggregateType();
-
- const std::string uniformElementName = fieldName + (field.isArray() ? ArrayString(arrayElement) : "");
- defineUniformBlockMembers(field.fields, uniformElementName, blockIndex, encoder, blockUniformIndexes, rowMajorLayout);
-
- encoder->exitAggregateType();
- }
- }
- else
+ if (d3dUniform->isSampler())
{
- bool isRowMajorMatrix = (gl::IsMatrixType(field.type) && inRowMajorLayout);
-
- sh::BlockMemberInfo memberInfo = encoder->encodeType(field.type, field.arraySize, isRowMajorMatrix);
-
- gl::LinkedUniform *newUniform = new gl::LinkedUniform(field.type, field.precision, fieldName, field.arraySize,
- blockIndex, memberInfo);
-
- // add to uniform list, but not index, since uniform block uniforms have no location
- blockUniformIndexes->push_back(mUniforms.size());
- mUniforms.push_back(newUniform);
+ assignSamplerRegisters(d3dUniform);
}
}
}
-bool ProgramD3D::defineUniformBlock(gl::InfoLog &infoLog, const gl::Shader &shader, const sh::InterfaceBlock &interfaceBlock,
- const gl::Caps &caps)
+void ProgramD3D::assignSamplerRegisters(const D3DUniform *d3dUniform)
{
- const ShaderD3D* shaderD3D = ShaderD3D::makeShaderD3D(shader.getImplementation());
+ ASSERT(d3dUniform->isSampler());
+ ASSERT(d3dUniform->vsRegisterIndex != GL_INVALID_INDEX ||
+ d3dUniform->psRegisterIndex != GL_INVALID_INDEX);
- // create uniform block entries if they do not exist
- if (getUniformBlockIndex(interfaceBlock.name) == GL_INVALID_INDEX)
+ if (d3dUniform->vsRegisterIndex != GL_INVALID_INDEX)
{
- std::vector<unsigned int> blockUniformIndexes;
- const unsigned int blockIndex = mUniformBlocks.size();
-
- // define member uniforms
- sh::BlockLayoutEncoder *encoder = NULL;
-
- if (interfaceBlock.layout == sh::BLOCKLAYOUT_STANDARD)
- {
- encoder = new sh::Std140BlockEncoder;
- }
- else
- {
- encoder = new sh::HLSLBlockEncoder(sh::HLSLBlockEncoder::ENCODE_PACKED);
- }
- ASSERT(encoder);
-
- defineUniformBlockMembers(interfaceBlock.fields, "", blockIndex, encoder, &blockUniformIndexes, interfaceBlock.isRowMajorLayout);
-
- size_t dataSize = encoder->getBlockSize();
-
- // create all the uniform blocks
- if (interfaceBlock.arraySize > 0)
- {
- for (unsigned int uniformBlockElement = 0; uniformBlockElement < interfaceBlock.arraySize; uniformBlockElement++)
- {
- gl::UniformBlock *newUniformBlock = new gl::UniformBlock(interfaceBlock.name, uniformBlockElement, dataSize);
- newUniformBlock->memberUniformIndexes = blockUniformIndexes;
- mUniformBlocks.push_back(newUniformBlock);
- }
- }
- else
- {
- gl::UniformBlock *newUniformBlock = new gl::UniformBlock(interfaceBlock.name, GL_INVALID_INDEX, dataSize);
- newUniformBlock->memberUniformIndexes = blockUniformIndexes;
- mUniformBlocks.push_back(newUniformBlock);
- }
+ AssignSamplers(d3dUniform->vsRegisterIndex, d3dUniform->type, d3dUniform->arraySize,
+ mSamplersVS, &mUsedVertexSamplerRange);
}
- if (interfaceBlock.staticUse)
+ if (d3dUniform->psRegisterIndex != GL_INVALID_INDEX)
{
- // Assign registers to the uniform blocks
- const GLuint blockIndex = getUniformBlockIndex(interfaceBlock.name);
- const unsigned int elementCount = std::max(1u, interfaceBlock.arraySize);
- ASSERT(blockIndex != GL_INVALID_INDEX);
- ASSERT(blockIndex + elementCount <= mUniformBlocks.size());
-
- unsigned int interfaceBlockRegister = shaderD3D->getInterfaceBlockRegister(interfaceBlock.name);
-
- for (unsigned int uniformBlockElement = 0; uniformBlockElement < elementCount; uniformBlockElement++)
- {
- gl::UniformBlock *uniformBlock = mUniformBlocks[blockIndex + uniformBlockElement];
- ASSERT(uniformBlock->name == interfaceBlock.name);
-
- if (!assignUniformBlockRegister(infoLog, uniformBlock, shader.getType(),
- interfaceBlockRegister + uniformBlockElement, caps))
- {
- return false;
- }
- }
+ AssignSamplers(d3dUniform->psRegisterIndex, d3dUniform->type, d3dUniform->arraySize,
+ mSamplersPS, &mUsedPixelSamplerRange);
}
-
- return true;
}
-bool ProgramD3D::assignSamplers(unsigned int startSamplerIndex,
- GLenum samplerType,
- unsigned int samplerCount,
- std::vector<Sampler> &outSamplers,
- GLuint *outUsedRange)
+// static
+void ProgramD3D::AssignSamplers(unsigned int startSamplerIndex,
+ GLenum samplerType,
+ unsigned int samplerCount,
+ std::vector<Sampler> &outSamplers,
+ GLuint *outUsedRange)
{
unsigned int samplerIndex = startSamplerIndex;
do
{
- if (samplerIndex < outSamplers.size())
- {
- Sampler& sampler = outSamplers[samplerIndex];
- sampler.active = true;
- sampler.textureType = GetTextureType(samplerType);
- sampler.logicalTextureUnit = 0;
- *outUsedRange = std::max(samplerIndex + 1, *outUsedRange);
- }
- else
- {
- return false;
- }
-
+ ASSERT(samplerIndex < outSamplers.size());
+ Sampler *sampler = &outSamplers[samplerIndex];
+ sampler->active = true;
+ sampler->textureType = gl::SamplerTypeToTextureType(samplerType);
+ sampler->logicalTextureUnit = 0;
+ *outUsedRange = std::max(samplerIndex + 1, *outUsedRange);
samplerIndex++;
} while (samplerIndex < startSamplerIndex + samplerCount);
-
- return true;
-}
-
-bool ProgramD3D::indexSamplerUniform(const gl::LinkedUniform &uniform, gl::InfoLog &infoLog, const gl::Caps &caps)
-{
- ASSERT(gl::IsSamplerType(uniform.type));
- ASSERT(uniform.vsRegisterIndex != GL_INVALID_INDEX || uniform.psRegisterIndex != GL_INVALID_INDEX);
-
- if (uniform.vsRegisterIndex != GL_INVALID_INDEX)
- {
- if (!assignSamplers(uniform.vsRegisterIndex, uniform.type, uniform.arraySize, mSamplersVS,
- &mUsedVertexSamplerRange))
- {
- infoLog.append("Vertex shader sampler count exceeds the maximum vertex texture units (%d).",
- mSamplersVS.size());
- return false;
- }
-
- unsigned int maxVertexVectors = mRenderer->getReservedVertexUniformVectors() + caps.maxVertexUniformVectors;
- if (uniform.vsRegisterIndex + uniform.registerCount > maxVertexVectors)
- {
- infoLog.append("Vertex shader active uniforms exceed GL_MAX_VERTEX_UNIFORM_VECTORS (%u)",
- caps.maxVertexUniformVectors);
- return false;
- }
- }
-
- if (uniform.psRegisterIndex != GL_INVALID_INDEX)
- {
- if (!assignSamplers(uniform.psRegisterIndex, uniform.type, uniform.arraySize, mSamplersPS,
- &mUsedPixelSamplerRange))
- {
- infoLog.append("Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (%d).",
- mSamplersPS.size());
- return false;
- }
-
- unsigned int maxFragmentVectors = mRenderer->getReservedFragmentUniformVectors() + caps.maxFragmentUniformVectors;
- if (uniform.psRegisterIndex + uniform.registerCount > maxFragmentVectors)
- {
- infoLog.append("Fragment shader active uniforms exceed GL_MAX_FRAGMENT_UNIFORM_VECTORS (%u)",
- caps.maxFragmentUniformVectors);
- return false;
- }
- }
-
- return true;
-}
-
-bool ProgramD3D::indexUniforms(gl::InfoLog &infoLog, const gl::Caps &caps)
-{
- for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
- {
- const gl::LinkedUniform &uniform = *mUniforms[uniformIndex];
-
- if (gl::IsSamplerType(uniform.type))
- {
- if (!indexSamplerUniform(uniform, infoLog, caps))
- {
- return false;
- }
- }
-
- for (unsigned int arrayElementIndex = 0; arrayElementIndex < uniform.elementCount(); arrayElementIndex++)
- {
- mUniformIndex.push_back(gl::VariableLocation(uniform.name, arrayElementIndex, uniformIndex));
- }
- }
-
- return true;
}
void ProgramD3D::reset()
{
- ProgramImpl::reset();
-
SafeDeleteContainer(mVertexExecutables);
SafeDeleteContainer(mPixelExecutables);
- SafeDelete(mGeometryExecutable);
- mTransformFeedbackBufferMode = GL_NONE;
+ for (auto &element : mGeometryExecutables)
+ {
+ SafeDelete(element);
+ }
mVertexHLSL.clear();
- mVertexWorkarounds.reset();
- mShaderVersion = 100;
+ mVertexWorkarounds = D3DCompilerWorkarounds();
mPixelHLSL.clear();
- mPixelWorkarounds.reset();
+ mPixelWorkarounds = D3DCompilerWorkarounds();
mUsesFragDepth = false;
mPixelShaderKey.clear();
mUsesPointSize = false;
+ mUsesFlatInterpolation = false;
+
+ SafeDeleteContainer(mD3DUniforms);
+ mD3DUniformBlocks.clear();
SafeDelete(mVertexUniformStorage);
SafeDelete(mFragmentUniformStorage);
@@ -1958,10 +2150,15 @@ void ProgramD3D::reset()
mSamplersVS.clear();
mUsedVertexSamplerRange = 0;
- mUsedPixelSamplerRange = 0;
- mDirtySamplerMapping = true;
+ mUsedPixelSamplerRange = 0;
+ mDirtySamplerMapping = true;
+ std::fill(mSemanticIndexes, mSemanticIndexes + ArraySize(mSemanticIndexes), -1);
std::fill(mAttributesByLayout, mAttributesByLayout + ArraySize(mAttributesByLayout), -1);
+
+ mStreamOutVaryings.clear();
+
+ mGeometryShaderPreamble.clear();
}
unsigned int ProgramD3D::getSerial() const
@@ -1974,6 +2171,27 @@ unsigned int ProgramD3D::issueSerial()
return mCurrentSerial++;
}
+void ProgramD3D::initSemanticIndex()
+{
+ const gl::Shader *vertexShader = mData.getAttachedVertexShader();
+ ASSERT(vertexShader != nullptr);
+
+ // Init semantic index
+ for (const sh::Attribute &attribute : mData.getAttributes())
+ {
+ int attributeIndex = attribute.location;
+ int index = vertexShader->getSemanticIndex(attribute.name);
+ int regs = gl::VariableRegisterCount(attribute.type);
+
+ for (int reg = 0; reg < regs; ++reg)
+ {
+ mSemanticIndexes[attributeIndex + reg] = index + reg;
+ }
+ }
+
+ initAttributesByLayout();
+}
+
void ProgramD3D::initAttributesByLayout()
{
for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
@@ -1981,25 +2199,142 @@ void ProgramD3D::initAttributesByLayout()
mAttributesByLayout[i] = i;
}
- std::sort(&mAttributesByLayout[0], &mAttributesByLayout[gl::MAX_VERTEX_ATTRIBS], AttributeSorter(mSemanticIndex));
+ std::sort(&mAttributesByLayout[0], &mAttributesByLayout[gl::MAX_VERTEX_ATTRIBS],
+ AttributeSorter(mSemanticIndexes));
}
-void ProgramD3D::sortAttributesByLayout(rx::TranslatedAttribute attributes[gl::MAX_VERTEX_ATTRIBS],
- int sortedSemanticIndices[gl::MAX_VERTEX_ATTRIBS]) const
+void ProgramD3D::sortAttributesByLayout(
+ const std::vector<TranslatedAttribute> &unsortedAttributes,
+ int sortedSemanticIndicesOut[gl::MAX_VERTEX_ATTRIBS],
+ const rx::TranslatedAttribute *sortedAttributesOut[gl::MAX_VERTEX_ATTRIBS]) const
{
- rx::TranslatedAttribute oldTranslatedAttributes[gl::MAX_VERTEX_ATTRIBS];
+ for (size_t attribIndex = 0; attribIndex < unsortedAttributes.size(); ++attribIndex)
+ {
+ int oldIndex = mAttributesByLayout[attribIndex];
+ sortedSemanticIndicesOut[attribIndex] = mSemanticIndexes[oldIndex];
+ sortedAttributesOut[attribIndex] = &unsortedAttributes[oldIndex];
+ }
+}
- for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
+void ProgramD3D::updateCachedInputLayout(const gl::State &state)
+{
+ mCachedInputLayout.clear();
+ const auto &vertexAttributes = state.getVertexArray()->getVertexAttributes();
+
+ for (unsigned int attributeIndex : angle::IterateBitSet(mData.getActiveAttribLocationsMask()))
{
- oldTranslatedAttributes[i] = attributes[i];
+ int semanticIndex = mSemanticIndexes[attributeIndex];
+
+ if (semanticIndex != -1)
+ {
+ if (mCachedInputLayout.size() < static_cast<size_t>(semanticIndex + 1))
+ {
+ mCachedInputLayout.resize(semanticIndex + 1, gl::VERTEX_FORMAT_INVALID);
+ }
+ mCachedInputLayout[semanticIndex] =
+ GetVertexFormatType(vertexAttributes[attributeIndex],
+ state.getVertexAttribCurrentValue(attributeIndex).Type);
+ }
}
+}
- for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
+void ProgramD3D::gatherTransformFeedbackVaryings(const VaryingPacking &varyingPacking)
+{
+ const auto &builtins = varyingPacking.builtins(SHADER_VERTEX);
+
+ const std::string &varyingSemantic =
+ GetVaryingSemantic(mRenderer->getMajorShaderModel(), usesPointSize());
+
+ // Gather the linked varyings that are used for transform feedback, they should all exist.
+ mStreamOutVaryings.clear();
+
+ const auto &tfVaryingNames = mData.getTransformFeedbackVaryingNames();
+ for (unsigned int outputSlot = 0; outputSlot < static_cast<unsigned int>(tfVaryingNames.size());
+ ++outputSlot)
+ {
+ const auto &tfVaryingName = tfVaryingNames[outputSlot];
+ if (tfVaryingName == "gl_Position")
+ {
+ if (builtins.glPosition.enabled)
+ {
+ mStreamOutVaryings.push_back(D3DVarying(builtins.glPosition.semantic,
+ builtins.glPosition.index, 4, outputSlot));
+ }
+ }
+ else if (tfVaryingName == "gl_FragCoord")
+ {
+ if (builtins.glFragCoord.enabled)
+ {
+ mStreamOutVaryings.push_back(D3DVarying(builtins.glFragCoord.semantic,
+ builtins.glFragCoord.index, 4, outputSlot));
+ }
+ }
+ else if (tfVaryingName == "gl_PointSize")
+ {
+ if (builtins.glPointSize.enabled)
+ {
+ mStreamOutVaryings.push_back(D3DVarying("PSIZE", 0, 1, outputSlot));
+ }
+ }
+ else
+ {
+ for (const PackedVaryingRegister &registerInfo : varyingPacking.getRegisterList())
+ {
+ const auto &varying = *registerInfo.packedVarying->varying;
+ GLenum transposedType = gl::TransposeMatrixType(varying.type);
+ int componentCount = gl::VariableColumnCount(transposedType);
+ ASSERT(!varying.isBuiltIn());
+
+ // Transform feedback for varying structs is underspecified.
+ // See Khronos bug 9856.
+ // TODO(jmadill): Figure out how to be spec-compliant here.
+ if (registerInfo.packedVarying->isStructField() || varying.isStruct())
+ continue;
+
+ // There can be more than one register assigned to a particular varying, and each
+ // register needs its own stream out entry.
+ if (tfVaryingName == varying.name)
+ {
+ mStreamOutVaryings.push_back(D3DVarying(
+ varyingSemantic, registerInfo.semanticIndex, componentCount, outputSlot));
+ }
+ }
+ }
+ }
+}
+
+D3DUniform *ProgramD3D::getD3DUniformFromLocation(GLint location)
+{
+ return mD3DUniforms[mData.getUniformLocations()[location].index];
+}
+
+bool ProgramD3D::getUniformBlockSize(const std::string &blockName, size_t *sizeOut) const
+{
+ std::string baseName = blockName;
+ gl::ParseAndStripArrayIndex(&baseName);
+
+ auto sizeIter = mBlockDataSizes.find(baseName);
+ if (sizeIter == mBlockDataSizes.end())
{
- int oldIndex = mAttributesByLayout[i];
- sortedSemanticIndices[i] = mSemanticIndex[oldIndex];
- attributes[i] = oldTranslatedAttributes[oldIndex];
+ *sizeOut = 0;
+ return false;
}
+
+ *sizeOut = sizeIter->second;
+ return true;
}
+bool ProgramD3D::getUniformBlockMemberInfo(const std::string &memberUniformName,
+ sh::BlockMemberInfo *memberInfoOut) const
+{
+ auto infoIter = mBlockInfo.find(memberUniformName);
+ if (infoIter == mBlockInfo.end())
+ {
+ *memberInfoOut = sh::BlockMemberInfo::getDefaultBlockInfo();
+ return false;
+ }
+
+ *memberInfoOut = infoIter->second;
+ return true;
+}
}
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/ProgramD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/ProgramD3D.h
index 6f3eade81d..3dfe52db1c 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/ProgramD3D.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/ProgramD3D.h
@@ -9,21 +9,15 @@
#ifndef LIBANGLE_RENDERER_D3D_PROGRAMD3D_H_
#define LIBANGLE_RENDERER_D3D_PROGRAMD3D_H_
+#include <string>
+#include <vector>
+
#include "compiler/translator/blocklayoutHLSL.h"
#include "libANGLE/Constants.h"
+#include "libANGLE/formatutils.h"
#include "libANGLE/renderer/ProgramImpl.h"
-#include "libANGLE/renderer/Workarounds.h"
#include "libANGLE/renderer/d3d/DynamicHLSL.h"
-
-#include <string>
-#include <vector>
-
-namespace gl
-{
-struct LinkedUniform;
-struct VariableLocation;
-struct VertexFormat;
-}
+#include "libANGLE/renderer/d3d/WorkaroundsD3D.h"
namespace rx
{
@@ -37,53 +31,155 @@ class ShaderExecutableD3D;
#define ANGLE_COMPILE_OPTIMIZATION_LEVEL D3DCOMPILE_OPTIMIZATION_LEVEL1
#endif
+// Helper struct representing a single shader uniform
+struct D3DUniform : angle::NonCopyable
+{
+ D3DUniform(GLenum typeIn,
+ const std::string &nameIn,
+ unsigned int arraySizeIn,
+ bool defaultBlock);
+ ~D3DUniform();
+
+ bool isSampler() const;
+ unsigned int elementCount() const { return std::max(1u, arraySize); }
+ bool isReferencedByVertexShader() const;
+ bool isReferencedByFragmentShader() const;
+
+ // Duplicated from the GL layer
+ GLenum type;
+ std::string name;
+ unsigned int arraySize;
+
+ // Pointer to a system copy of the data.
+ // TODO(jmadill): remove this in favor of gl::LinkedUniform::data().
+ uint8_t *data;
+
+ // Has the data been updated since the last sync?
+ bool dirty;
+
+ // Register information.
+ unsigned int vsRegisterIndex;
+ unsigned int psRegisterIndex;
+ unsigned int registerCount;
+
+ // Register "elements" are used for uniform structs in ES3, to appropriately identify single
+ // uniforms
+ // inside aggregate types, which are packed according C-like structure rules.
+ unsigned int registerElement;
+};
+
+struct D3DUniformBlock
+{
+ D3DUniformBlock() : vsRegisterIndex(GL_INVALID_INDEX), psRegisterIndex(GL_INVALID_INDEX) {}
+
+ bool vertexStaticUse() const { return vsRegisterIndex != GL_INVALID_INDEX; }
+
+ bool fragmentStaticUse() const { return psRegisterIndex != GL_INVALID_INDEX; }
+
+ unsigned int vsRegisterIndex;
+ unsigned int psRegisterIndex;
+};
+
+struct D3DVarying final
+{
+ D3DVarying();
+ D3DVarying(const std::string &semanticNameIn,
+ unsigned int semanticIndexIn,
+ unsigned int componentCountIn,
+ unsigned int outputSlotIn);
+
+ D3DVarying(const D3DVarying &) = default;
+ D3DVarying &operator=(const D3DVarying &) = default;
+
+ std::string semanticName;
+ unsigned int semanticIndex;
+ unsigned int componentCount;
+ unsigned int outputSlot;
+};
+
+class ProgramD3DMetadata : angle::NonCopyable
+{
+ public:
+ ProgramD3DMetadata(int rendererMajorShaderModel,
+ const std::string &shaderModelSuffix,
+ bool usesInstancedPointSpriteEmulation,
+ bool usesViewScale,
+ const ShaderD3D *vertexShader,
+ const ShaderD3D *fragmentShader);
+
+ int getRendererMajorShaderModel() const;
+ bool usesBroadcast(const gl::Data &data) const;
+ bool usesFragDepth(const gl::Program::Data &programData) const;
+ bool usesPointCoord() const;
+ bool usesFragCoord() const;
+ bool usesPointSize() const;
+ bool usesInsertedPointCoordValue() const;
+ bool usesViewScale() const;
+ bool addsPointCoordToVertexShader() const;
+ bool usesTransformFeedbackGLPosition() const;
+ bool usesSystemValuePointSize() const;
+ bool usesMultipleFragmentOuts() const;
+ GLint getMajorShaderVersion() const;
+ const ShaderD3D *getFragmentShader() const;
+
+ private:
+ const int mRendererMajorShaderModel;
+ const std::string mShaderModelSuffix;
+ const bool mUsesInstancedPointSpriteEmulation;
+ const bool mUsesViewScale;
+ const ShaderD3D *mVertexShader;
+ const ShaderD3D *mFragmentShader;
+};
+
class ProgramD3D : public ProgramImpl
{
public:
- ProgramD3D(RendererD3D *renderer);
+ typedef int SemanticIndexArray[gl::MAX_VERTEX_ATTRIBS];
+
+ ProgramD3D(const gl::Program::Data &data, RendererD3D *renderer);
virtual ~ProgramD3D();
const std::vector<PixelShaderOutputVariable> &getPixelShaderKey() { return mPixelShaderKey; }
- int getShaderVersion() const { return mShaderVersion; }
- GLenum getTransformFeedbackBufferMode() const { return mTransformFeedbackBufferMode; }
- GLint getSamplerMapping(gl::SamplerType type, unsigned int samplerIndex, const gl::Caps &caps) const;
+ GLint getSamplerMapping(gl::SamplerType type,
+ unsigned int samplerIndex,
+ const gl::Caps &caps) const;
GLenum getSamplerTextureType(gl::SamplerType type, unsigned int samplerIndex) const;
GLint getUsedSamplerRange(gl::SamplerType type) const;
void updateSamplerMapping();
- bool validateSamplers(gl::InfoLog *infoLog, const gl::Caps &caps);
bool usesPointSize() const { return mUsesPointSize; }
bool usesPointSpriteEmulation() const;
- bool usesGeometryShader() const;
+ bool usesGeometryShader(GLenum drawMode) const;
bool usesInstancedPointSpriteEmulation() const;
- GLenum getBinaryFormat() { return GL_PROGRAM_BINARY_ANGLE; }
- LinkResult load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream);
- gl::Error save(gl::BinaryOutputStream *stream);
-
- gl::Error getPixelExecutableForFramebuffer(const gl::Framebuffer *fbo, ShaderExecutableD3D **outExectuable);
- gl::Error getPixelExecutableForOutputLayout(const std::vector<GLenum> &outputLayout, ShaderExecutableD3D **outExectuable, gl::InfoLog *infoLog);
- gl::Error getVertexExecutableForInputLayout(const gl::VertexFormat inputLayout[gl::MAX_VERTEX_ATTRIBS], ShaderExecutableD3D **outExectuable, gl::InfoLog *infoLog);
- ShaderExecutableD3D *getGeometryExecutable() const { return mGeometryExecutable; }
-
- LinkResult compileProgramExecutables(gl::InfoLog &infoLog, gl::Shader *fragmentShader, gl::Shader *vertexShader,
- int registers);
-
- LinkResult link(const gl::Data &data, gl::InfoLog &infoLog,
- gl::Shader *fragmentShader, gl::Shader *vertexShader,
- const std::vector<std::string> &transformFeedbackVaryings,
- GLenum transformFeedbackBufferMode,
- int *registers, std::vector<gl::LinkedVarying> *linkedVaryings,
- std::map<int, gl::VariableLocation> *outputVariables);
-
- void getInputLayoutSignature(const gl::VertexFormat inputLayout[], GLenum signature[]) const;
+ LinkResult load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream) override;
+ gl::Error save(gl::BinaryOutputStream *stream) override;
+ void setBinaryRetrievableHint(bool retrievable) override;
+
+ gl::Error getPixelExecutableForFramebuffer(const gl::Framebuffer *fbo,
+ ShaderExecutableD3D **outExectuable);
+ gl::Error getPixelExecutableForOutputLayout(const std::vector<GLenum> &outputLayout,
+ ShaderExecutableD3D **outExectuable,
+ gl::InfoLog *infoLog);
+ gl::Error getVertexExecutableForInputLayout(const gl::InputLayout &inputLayout,
+ ShaderExecutableD3D **outExectuable,
+ gl::InfoLog *infoLog);
+ gl::Error getGeometryExecutableForPrimitiveType(const gl::Data &data,
+ GLenum drawMode,
+ ShaderExecutableD3D **outExecutable,
+ gl::InfoLog *infoLog);
+
+ LinkResult link(const gl::Data &data, gl::InfoLog &infoLog) override;
+ GLboolean validate(const gl::Caps &caps, gl::InfoLog *infoLog) override;
+
+ bool getUniformBlockSize(const std::string &blockName, size_t *sizeOut) const override;
+ bool getUniformBlockMemberInfo(const std::string &memberUniformName,
+ sh::BlockMemberInfo *memberInfoOut) const override;
void initializeUniformStorage();
- gl::Error applyUniforms();
- gl::Error applyUniformBuffers(const gl::Data &data, GLuint uniformBlockBindings[]) override;
- bool assignUniformBlockRegister(gl::InfoLog &infoLog, gl::UniformBlock *uniformBlock, GLenum shader,
- unsigned int registerIndex, const gl::Caps &caps);
+ gl::Error applyUniforms(GLenum drawMode);
+ gl::Error applyUniformBuffers(const gl::Data &data);
void dirtyAllUniforms();
void setUniform1fv(GLint location, GLsizei count, const GLfloat *v);
@@ -98,63 +194,99 @@ class ProgramD3D : public ProgramImpl
void setUniform2uiv(GLint location, GLsizei count, const GLuint *v);
void setUniform3uiv(GLint location, GLsizei count, const GLuint *v);
void setUniform4uiv(GLint location, GLsizei count, const GLuint *v);
- void setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
- void setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
- void setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
- void setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
- void setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
- void setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
- void setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
- void setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
- void setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
-
- void getUniformfv(GLint location, GLfloat *params);
- void getUniformiv(GLint location, GLint *params);
- void getUniformuiv(GLint location, GLuint *params);
+ void setUniformMatrix2fv(GLint location,
+ GLsizei count,
+ GLboolean transpose,
+ const GLfloat *value);
+ void setUniformMatrix3fv(GLint location,
+ GLsizei count,
+ GLboolean transpose,
+ const GLfloat *value);
+ void setUniformMatrix4fv(GLint location,
+ GLsizei count,
+ GLboolean transpose,
+ const GLfloat *value);
+ void setUniformMatrix2x3fv(GLint location,
+ GLsizei count,
+ GLboolean transpose,
+ const GLfloat *value);
+ void setUniformMatrix3x2fv(GLint location,
+ GLsizei count,
+ GLboolean transpose,
+ const GLfloat *value);
+ void setUniformMatrix2x4fv(GLint location,
+ GLsizei count,
+ GLboolean transpose,
+ const GLfloat *value);
+ void setUniformMatrix4x2fv(GLint location,
+ GLsizei count,
+ GLboolean transpose,
+ const GLfloat *value);
+ void setUniformMatrix3x4fv(GLint location,
+ GLsizei count,
+ GLboolean transpose,
+ const GLfloat *value);
+ void setUniformMatrix4x3fv(GLint location,
+ GLsizei count,
+ GLboolean transpose,
+ const GLfloat *value);
+
+ void setUniformBlockBinding(GLuint uniformBlockIndex, GLuint uniformBlockBinding) override;
const UniformStorageD3D &getVertexUniformStorage() const { return *mVertexUniformStorage; }
const UniformStorageD3D &getFragmentUniformStorage() const { return *mFragmentUniformStorage; }
- bool linkUniforms(gl::InfoLog &infoLog, const gl::Shader &vertexShader, const gl::Shader &fragmentShader,
- const gl::Caps &caps);
- bool defineUniformBlock(gl::InfoLog &infoLog, const gl::Shader &shader, const sh::InterfaceBlock &interfaceBlock, const gl::Caps &caps);
+ unsigned int getSerial() const;
- void reset();
+ void sortAttributesByLayout(
+ const std::vector<TranslatedAttribute> &unsortedAttributes,
+ int sortedSemanticIndicesOut[gl::MAX_VERTEX_ATTRIBS],
+ const rx::TranslatedAttribute *sortedAttributesOut[gl::MAX_VERTEX_ATTRIBS]) const;
+ const SemanticIndexArray &getSemanticIndexes() const { return mSemanticIndexes; }
+ const SemanticIndexArray &getAttributesByLayout() const { return mAttributesByLayout; }
- unsigned int getSerial() const;
+ void updateCachedInputLayout(const gl::State &state);
+ const gl::InputLayout &getCachedInputLayout() const { return mCachedInputLayout; }
- void initAttributesByLayout();
- void sortAttributesByLayout(rx::TranslatedAttribute attributes[gl::MAX_VERTEX_ATTRIBS],
- int sortedSemanticIndices[gl::MAX_VERTEX_ATTRIBS]) const;
+ bool isSamplerMappingDirty() { return mDirtySamplerMapping; }
private:
class VertexExecutable
{
public:
- VertexExecutable(const gl::VertexFormat inputLayout[gl::MAX_VERTEX_ATTRIBS],
- const GLenum signature[gl::MAX_VERTEX_ATTRIBS],
+ typedef std::vector<bool> Signature;
+
+ VertexExecutable(const gl::InputLayout &inputLayout,
+ const Signature &signature,
ShaderExecutableD3D *shaderExecutable);
~VertexExecutable();
- bool matchesSignature(const GLenum convertedLayout[gl::MAX_VERTEX_ATTRIBS]) const;
+ bool matchesSignature(const Signature &signature) const;
+ static void getSignature(RendererD3D *renderer,
+ const gl::InputLayout &inputLayout,
+ Signature *signatureOut);
- const gl::VertexFormat *inputs() const { return mInputs; }
- const GLenum *signature() const { return mSignature; }
+ const gl::InputLayout &inputs() const { return mInputs; }
+ const Signature &signature() const { return mSignature; }
ShaderExecutableD3D *shaderExecutable() const { return mShaderExecutable; }
private:
- gl::VertexFormat mInputs[gl::MAX_VERTEX_ATTRIBS];
- GLenum mSignature[gl::MAX_VERTEX_ATTRIBS];
+ gl::InputLayout mInputs;
+ Signature mSignature;
ShaderExecutableD3D *mShaderExecutable;
};
class PixelExecutable
{
public:
- PixelExecutable(const std::vector<GLenum> &outputSignature, ShaderExecutableD3D *shaderExecutable);
+ PixelExecutable(const std::vector<GLenum> &outputSignature,
+ ShaderExecutableD3D *shaderExecutable);
~PixelExecutable();
- bool matchesSignature(const std::vector<GLenum> &signature) const { return mOutputSignature == signature; }
+ bool matchesSignature(const std::vector<GLenum> &signature) const
+ {
+ return mOutputSignature == signature;
+ }
const std::vector<GLenum> &outputSignature() const { return mOutputSignature; }
ShaderExecutableD3D *shaderExecutable() const { return mShaderExecutable; }
@@ -173,34 +305,57 @@ class ProgramD3D : public ProgramImpl
GLenum textureType;
};
- void defineUniformBase(const ShaderD3D *shader, const sh::Uniform &uniform, unsigned int uniformRegister);
- void defineUniform(const ShaderD3D *shader, const sh::ShaderVariable &uniform, const std::string &fullName,
- sh::HLSLBlockEncoder *encoder);
- bool indexSamplerUniform(const gl::LinkedUniform &uniform, gl::InfoLog &infoLog, const gl::Caps &caps);
- bool indexUniforms(gl::InfoLog &infoLog, const gl::Caps &caps);
- static bool assignSamplers(unsigned int startSamplerIndex, GLenum samplerType, unsigned int samplerCount,
- std::vector<Sampler> &outSamplers, GLuint *outUsedRange);
+ typedef std::map<std::string, D3DUniform *> D3DUniformMap;
+
+ void defineUniformsAndAssignRegisters();
+ void defineUniformBase(const gl::Shader *shader,
+ const sh::Uniform &uniform,
+ D3DUniformMap *uniformMap);
+ void defineUniform(GLenum shaderType,
+ const sh::ShaderVariable &uniform,
+ const std::string &fullName,
+ sh::HLSLBlockEncoder *encoder,
+ D3DUniformMap *uniformMap);
+ void assignAllSamplerRegisters();
+ void assignSamplerRegisters(const D3DUniform *d3dUniform);
+
+ static void AssignSamplers(unsigned int startSamplerIndex,
+ GLenum samplerType,
+ unsigned int samplerCount,
+ std::vector<Sampler> &outSamplers,
+ GLuint *outUsedRange);
template <typename T>
- void setUniform(GLint location, GLsizei count, const T* v, GLenum targetUniformType);
+ void setUniform(GLint location, GLsizei count, const T *v, GLenum targetUniformType);
template <int cols, int rows>
- void setUniformMatrixfv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value, GLenum targetUniformType);
+ void setUniformMatrixfv(GLint location,
+ GLsizei count,
+ GLboolean transpose,
+ const GLfloat *value,
+ GLenum targetUniformType);
- template <typename T>
- void getUniformv(GLint location, T *params, GLenum uniformType);
+ LinkResult compileProgramExecutables(const gl::Data &data, gl::InfoLog &infoLog);
- template <typename VarT>
- void defineUniformBlockMembers(const std::vector<VarT> &fields, const std::string &prefix, int blockIndex,
- sh::BlockLayoutEncoder *encoder, std::vector<unsigned int> *blockUniformIndexes,
- bool inRowMajorLayout);
+ void gatherTransformFeedbackVaryings(const VaryingPacking &varyings);
+ D3DUniform *getD3DUniformByName(const std::string &name);
+ D3DUniform *getD3DUniformFromLocation(GLint location);
+
+ void initSemanticIndex();
+ void initAttributesByLayout();
+
+ void reset();
+ void assignUniformBlockRegisters();
+
+ void initUniformBlockInfo();
+ size_t getUniformBlockInfo(const sh::InterfaceBlock &interfaceBlock);
RendererD3D *mRenderer;
DynamicHLSL *mDynamicHLSL;
std::vector<VertexExecutable *> mVertexExecutables;
std::vector<PixelExecutable *> mPixelExecutables;
- ShaderExecutableD3D *mGeometryExecutable;
+ std::vector<ShaderExecutableD3D *> mGeometryExecutables;
std::string mVertexHLSL;
D3DCompilerWorkarounds mVertexWorkarounds;
@@ -210,35 +365,46 @@ class ProgramD3D : public ProgramImpl
bool mUsesFragDepth;
std::vector<PixelShaderOutputVariable> mPixelShaderKey;
+ // Common code for all dynamic geometry shaders. Consists mainly of the GS input and output
+ // structures, built from the linked varying info. We store the string itself instead of the
+ // packed varyings for simplicity.
+ std::string mGeometryShaderPreamble;
+
bool mUsesPointSize;
+ bool mUsesFlatInterpolation;
UniformStorageD3D *mVertexUniformStorage;
UniformStorageD3D *mFragmentUniformStorage;
- GLenum mTransformFeedbackBufferMode;
-
std::vector<Sampler> mSamplersPS;
std::vector<Sampler> mSamplersVS;
GLuint mUsedVertexSamplerRange;
GLuint mUsedPixelSamplerRange;
bool mDirtySamplerMapping;
- // Cache for validateSamplers
- std::vector<GLenum> mTextureUnitTypesCache;
-
// Cache for getPixelExecutableForFramebuffer
std::vector<GLenum> mPixelShaderOutputFormatCache;
- int mShaderVersion;
-
- int mAttributesByLayout[gl::MAX_VERTEX_ATTRIBS];
+ SemanticIndexArray mSemanticIndexes;
+ SemanticIndexArray mAttributesByLayout;
unsigned int mSerial;
+ std::vector<GLint> mVertexUBOCache;
+ std::vector<GLint> mFragmentUBOCache;
+ VertexExecutable::Signature mCachedVertexSignature;
+ gl::InputLayout mCachedInputLayout;
+
+ std::vector<D3DVarying> mStreamOutVaryings;
+ std::vector<D3DUniform *> mD3DUniforms;
+ std::vector<D3DUniformBlock> mD3DUniformBlocks;
+
+ std::map<std::string, sh::BlockMemberInfo> mBlockInfo;
+ std::map<std::string, size_t> mBlockDataSizes;
+
static unsigned int issueSerial();
static unsigned int mCurrentSerial;
};
-
}
-#endif // LIBANGLE_RENDERER_D3D_PROGRAMD3D_H_
+#endif // LIBANGLE_RENDERER_D3D_PROGRAMD3D_H_
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/RenderTargetD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/RenderTargetD3D.h
index fe6afcecae..b2d895d9c6 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/RenderTargetD3D.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/RenderTargetD3D.h
@@ -12,11 +12,12 @@
#include "common/angleutils.h"
#include "libANGLE/angletypes.h"
+#include "libANGLE/FramebufferAttachment.h"
namespace rx
{
-class RenderTargetD3D : angle::NonCopyable
+class RenderTargetD3D : public FramebufferAttachmentRenderTarget
{
public:
RenderTargetD3D();
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/RenderbufferD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/RenderbufferD3D.cpp
index c91fedff06..991801a091 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/RenderbufferD3D.cpp
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/RenderbufferD3D.cpp
@@ -9,25 +9,22 @@
#include "libANGLE/renderer/d3d/RenderbufferD3D.h"
+#include "libANGLE/Image.h"
+#include "libANGLE/renderer/d3d/EGLImageD3D.h"
#include "libANGLE/renderer/d3d/RendererD3D.h"
#include "libANGLE/renderer/d3d/RenderTargetD3D.h"
namespace rx
{
-RenderbufferD3D::RenderbufferD3D(RendererD3D *renderer) : mRenderer(renderer)
+RenderbufferD3D::RenderbufferD3D(RendererD3D *renderer)
+ : mRenderer(renderer), mRenderTarget(nullptr), mImage(nullptr)
{
- mRenderTarget = NULL;
}
RenderbufferD3D::~RenderbufferD3D()
{
SafeDelete(mRenderTarget);
-}
-
-RenderbufferD3D *RenderbufferD3D::makeRenderbufferD3D(RenderbufferImpl *renderbuffer)
-{
- ASSERT(HAS_DYNAMIC_TYPE(RenderbufferD3D*, renderbuffer));
- return static_cast<RenderbufferD3D*>(renderbuffer);
+ mImage = nullptr;
}
gl::Error RenderbufferD3D::setStorage(GLenum internalformat, size_t width, size_t height)
@@ -47,27 +44,58 @@ gl::Error RenderbufferD3D::setStorageMultisample(size_t samples, GLenum internal
creationFormat = GL_DEPTH24_STENCIL8_OES;
}
+ // ANGLE_framebuffer_multisample states GL_OUT_OF_MEMORY is generated on a failure to create
+ // the specified storage.
+ // Because ES 3.0 already knows the exact number of supported samples, it would already have been
+ // validated and generated GL_INVALID_VALUE.
+ const gl::TextureCaps &formatCaps = mRenderer->getRendererTextureCaps().get(creationFormat);
+ if (samples > formatCaps.getMaxSamples())
+ {
+ return gl::Error(GL_OUT_OF_MEMORY, "Renderbuffer format does not support %u samples, %u is the maximum.",
+ samples, formatCaps.getMaxSamples());
+ }
+
RenderTargetD3D *newRT = NULL;
- gl::Error error = mRenderer->createRenderTarget(width, height, creationFormat, samples, &newRT);
+ gl::Error error =
+ mRenderer->createRenderTarget(static_cast<int>(width), static_cast<int>(height),
+ creationFormat, static_cast<GLsizei>(samples), &newRT);
if (error.isError())
{
return error;
}
SafeDelete(mRenderTarget);
+ mImage = nullptr;
mRenderTarget = newRT;
return gl::Error(GL_NO_ERROR);
}
-RenderTargetD3D *RenderbufferD3D::getRenderTarget()
+gl::Error RenderbufferD3D::setStorageEGLImageTarget(egl::Image *image)
+{
+ mImage = GetImplAs<EGLImageD3D>(image);
+ SafeDelete(mRenderTarget);
+
+ return gl::Error(GL_NO_ERROR);
+}
+
+gl::Error RenderbufferD3D::getRenderTarget(RenderTargetD3D **outRenderTarget)
{
- return mRenderTarget;
+ if (mImage)
+ {
+ return mImage->getRenderTarget(outRenderTarget);
+ }
+ else
+ {
+ *outRenderTarget = mRenderTarget;
+ return gl::Error(GL_NO_ERROR);
+ }
}
-unsigned int RenderbufferD3D::getRenderTargetSerial() const
+gl::Error RenderbufferD3D::getAttachmentRenderTarget(const gl::FramebufferAttachment::Target &target,
+ FramebufferAttachmentRenderTarget **rtOut)
{
- return (mRenderTarget ? mRenderTarget->getSerial() : 0);
+ return getRenderTarget(reinterpret_cast<RenderTargetD3D **>(rtOut));
}
}
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/RenderbufferD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/RenderbufferD3D.h
index 4c4b998683..20f6a10b2d 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/RenderbufferD3D.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/RenderbufferD3D.h
@@ -16,6 +16,7 @@
namespace rx
{
+class EGLImageD3D;
class RendererD3D;
class RenderTargetD3D;
class SwapChainD3D;
@@ -26,18 +27,23 @@ class RenderbufferD3D : public RenderbufferImpl
RenderbufferD3D(RendererD3D *renderer);
virtual ~RenderbufferD3D();
- static RenderbufferD3D *makeRenderbufferD3D(RenderbufferImpl *renderbuffer);
+ gl::Error setStorage(GLenum internalformat, size_t width, size_t height) override;
+ gl::Error setStorageMultisample(size_t samples,
+ GLenum internalformat,
+ size_t width,
+ size_t height) override;
+ gl::Error setStorageEGLImageTarget(egl::Image *image) override;
- virtual gl::Error setStorage(GLenum internalformat, size_t width, size_t height) override;
- virtual gl::Error setStorageMultisample(size_t samples, GLenum internalformat, size_t width, size_t height) override;
-
- RenderTargetD3D *getRenderTarget();
- unsigned int getRenderTargetSerial() const;
+ gl::Error getRenderTarget(RenderTargetD3D **outRenderTarget);
+ gl::Error getAttachmentRenderTarget(const gl::FramebufferAttachment::Target &target,
+ FramebufferAttachmentRenderTarget **rtOut) override;
private:
RendererD3D *mRenderer;
RenderTargetD3D *mRenderTarget;
+ EGLImageD3D *mImage;
};
+
}
#endif // LIBANGLE_RENDERER_D3D_RENDERBUFFERD3D_H_
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/RendererD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/RendererD3D.cpp
index 2ce0ce5a1b..105587f62c 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/RendererD3D.cpp
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/RendererD3D.cpp
@@ -8,18 +8,22 @@
#include "libANGLE/renderer/d3d/RendererD3D.h"
+#include "common/debug.h"
#include "common/MemoryBuffer.h"
#include "common/utilities.h"
#include "libANGLE/Display.h"
+#include "libANGLE/formatutils.h"
#include "libANGLE/Framebuffer.h"
#include "libANGLE/FramebufferAttachment.h"
-#include "libANGLE/ResourceManager.h"
-#include "libANGLE/State.h"
-#include "libANGLE/VertexArray.h"
-#include "libANGLE/formatutils.h"
#include "libANGLE/renderer/d3d/BufferD3D.h"
+#include "libANGLE/renderer/d3d/DeviceD3D.h"
#include "libANGLE/renderer/d3d/DisplayD3D.h"
#include "libANGLE/renderer/d3d/IndexDataManager.h"
+#include "libANGLE/renderer/d3d/ProgramD3D.h"
+#include "libANGLE/renderer/d3d/SamplerD3D.h"
+#include "libANGLE/ResourceManager.h"
+#include "libANGLE/State.h"
+#include "libANGLE/VertexArray.h"
namespace rx
{
@@ -30,12 +34,17 @@ namespace
// release and recreate the scratch buffer. This ensures we don't have a
// degenerate case where we are stuck hogging memory.
const int ScratchMemoryBufferLifetime = 1000;
-}
+
+} // anonymous namespace
RendererD3D::RendererD3D(egl::Display *display)
: mDisplay(display),
mDeviceLost(false),
- mScratchMemoryBufferResetCounter(0)
+ mAnnotator(nullptr),
+ mPresentPathFastEnabled(false),
+ mScratchMemoryBufferResetCounter(0),
+ mWorkaroundsInitialized(false),
+ mDisjoint(false)
{
}
@@ -47,35 +56,85 @@ RendererD3D::~RendererD3D()
void RendererD3D::cleanup()
{
mScratchMemoryBuffer.resize(0);
- for (auto it = mIncompleteTextures.begin(); it != mIncompleteTextures.end(); ++it)
+ for (auto &incompleteTexture : mIncompleteTextures)
{
- it->second.set(NULL);
+ incompleteTexture.second.set(NULL);
}
mIncompleteTextures.clear();
+
+ if (mAnnotator != nullptr)
+ {
+ gl::UninitializeDebugAnnotations();
+ SafeDelete(mAnnotator);
+ }
+}
+
+SamplerImpl *RendererD3D::createSampler()
+{
+ return new SamplerD3D();
}
-// static
-RendererD3D *RendererD3D::makeRendererD3D(Renderer *renderer)
+gl::Error RendererD3D::drawArrays(const gl::Data &data, GLenum mode, GLint first, GLsizei count)
{
- ASSERT(HAS_DYNAMIC_TYPE(RendererD3D*, renderer));
- return static_cast<RendererD3D*>(renderer);
+ return genericDrawArrays(data, mode, first, count, 0);
+}
+
+gl::Error RendererD3D::drawArraysInstanced(const gl::Data &data,
+ GLenum mode,
+ GLint first,
+ GLsizei count,
+ GLsizei instanceCount)
+{
+ return genericDrawArrays(data, mode, first, count, instanceCount);
}
gl::Error RendererD3D::drawElements(const gl::Data &data,
- GLenum mode, GLsizei count, GLenum type,
- const GLvoid *indices, GLsizei instances,
- const RangeUI &indexRange)
+ GLenum mode,
+ GLsizei count,
+ GLenum type,
+ const GLvoid *indices,
+ const gl::IndexRange &indexRange)
{
- if (data.state->isPrimitiveRestartEnabled())
- {
- UNIMPLEMENTED();
- return gl::Error(GL_INVALID_OPERATION, "Primitive restart not implemented");
- }
+ return genericDrawElements(data, mode, count, type, indices, 0, indexRange);
+}
+
+gl::Error RendererD3D::drawElementsInstanced(const gl::Data &data,
+ GLenum mode,
+ GLsizei count,
+ GLenum type,
+ const GLvoid *indices,
+ GLsizei instances,
+ const gl::IndexRange &indexRange)
+{
+ return genericDrawElements(data, mode, count, type, indices, instances, indexRange);
+}
+
+gl::Error RendererD3D::drawRangeElements(const gl::Data &data,
+ GLenum mode,
+ GLuint start,
+ GLuint end,
+ GLsizei count,
+ GLenum type,
+ const GLvoid *indices,
+ const gl::IndexRange &indexRange)
+{
+ return genericDrawElements(data, mode, count, type, indices, 0, indexRange);
+}
+gl::Error RendererD3D::genericDrawElements(const gl::Data &data,
+ GLenum mode,
+ GLsizei count,
+ GLenum type,
+ const GLvoid *indices,
+ GLsizei instances,
+ const gl::IndexRange &indexRange)
+{
gl::Program *program = data.state->getProgram();
- ASSERT(program != NULL);
+ ASSERT(program != nullptr);
+ ProgramD3D *programD3D = GetImplAs<ProgramD3D>(program);
+ bool usesPointSize = programD3D->usesPointSize();
- program->updateSamplerMapping();
+ programD3D->updateSamplerMapping();
gl::Error error = generateSwizzles(data);
if (error.isError())
@@ -83,27 +142,21 @@ gl::Error RendererD3D::drawElements(const gl::Data &data,
return error;
}
- if (!applyPrimitiveType(mode, count, program->usesPointSize()))
+ if (!applyPrimitiveType(mode, count, usesPointSize))
{
return gl::Error(GL_NO_ERROR);
}
- error = applyRenderTarget(data, mode, false);
- if (error.isError())
- {
- return error;
- }
-
- error = applyState(data, mode);
+ error = updateState(data, mode);
if (error.isError())
{
return error;
}
- gl::VertexArray *vao = data.state->getVertexArray();
TranslatedIndexData indexInfo;
indexInfo.indexRange = indexRange;
- error = applyIndexBuffer(indices, vao->getElementArrayBuffer(), count, mode, type, &indexInfo);
+
+ error = applyIndexBuffer(data, indices, count, mode, type, &indexInfo);
if (error.isError())
{
return error;
@@ -114,26 +167,27 @@ gl::Error RendererD3D::drawElements(const gl::Data &data,
// layer.
ASSERT(!data.state->isTransformFeedbackActiveUnpaused());
- GLsizei vertexCount = indexInfo.indexRange.length() + 1;
- error = applyVertexBuffer(*data.state, mode, indexInfo.indexRange.start, vertexCount, instances);
+ size_t vertexCount = indexInfo.indexRange.vertexCount();
+ error = applyVertexBuffer(*data.state, mode, static_cast<GLsizei>(indexInfo.indexRange.start),
+ static_cast<GLsizei>(vertexCount), instances, &indexInfo);
if (error.isError())
{
return error;
}
- error = applyShaders(data);
+ error = applyTextures(data);
if (error.isError())
{
return error;
}
- error = applyTextures(data);
+ error = applyShaders(data, mode);
if (error.isError())
{
return error;
}
- error = program->applyUniformBuffers(data);
+ error = programD3D->applyUniformBuffers(data);
if (error.isError())
{
return error;
@@ -141,7 +195,7 @@ gl::Error RendererD3D::drawElements(const gl::Data &data,
if (!skipDraw(data, mode))
{
- error = drawElements(mode, count, type, indices, vao->getElementArrayBuffer(), indexInfo, instances);
+ error = drawElementsImpl(data, indexInfo, mode, count, type, indices, instances);
if (error.isError())
{
return error;
@@ -151,14 +205,18 @@ gl::Error RendererD3D::drawElements(const gl::Data &data,
return gl::Error(GL_NO_ERROR);
}
-gl::Error RendererD3D::drawArrays(const gl::Data &data,
- GLenum mode, GLint first,
- GLsizei count, GLsizei instances)
+gl::Error RendererD3D::genericDrawArrays(const gl::Data &data,
+ GLenum mode,
+ GLint first,
+ GLsizei count,
+ GLsizei instances)
{
gl::Program *program = data.state->getProgram();
- ASSERT(program != NULL);
+ ASSERT(program != nullptr);
+ ProgramD3D *programD3D = GetImplAs<ProgramD3D>(program);
+ bool usesPointSize = programD3D->usesPointSize();
- program->updateSamplerMapping();
+ programD3D->updateSamplerMapping();
gl::Error error = generateSwizzles(data);
if (error.isError())
@@ -166,18 +224,12 @@ gl::Error RendererD3D::drawArrays(const gl::Data &data,
return error;
}
- if (!applyPrimitiveType(mode, count, program->usesPointSize()))
+ if (!applyPrimitiveType(mode, count, usesPointSize))
{
return gl::Error(GL_NO_ERROR);
}
- error = applyRenderTarget(data, mode, false);
- if (error.isError())
- {
- return error;
- }
-
- error = applyState(data, mode);
+ error = updateState(data, mode);
if (error.isError())
{
return error;
@@ -185,25 +237,25 @@ gl::Error RendererD3D::drawArrays(const gl::Data &data,
applyTransformFeedbackBuffers(*data.state);
- error = applyVertexBuffer(*data.state, mode, first, count, instances);
+ error = applyVertexBuffer(*data.state, mode, first, count, instances, nullptr);
if (error.isError())
{
return error;
}
- error = applyShaders(data);
+ error = applyTextures(data);
if (error.isError())
{
return error;
}
- error = applyTextures(data);
+ error = applyShaders(data, mode);
if (error.isError())
{
return error;
}
- error = program->applyUniformBuffers(data);
+ error = programD3D->applyUniformBuffers(data);
if (error.isError())
{
return error;
@@ -211,7 +263,7 @@ gl::Error RendererD3D::drawArrays(const gl::Data &data,
if (!skipDraw(data, mode))
{
- error = drawArrays(data, mode, count, instances, program->usesPointSize());
+ error = drawArraysImpl(data, mode, count, instances);
if (error.isError())
{
return error;
@@ -228,19 +280,19 @@ gl::Error RendererD3D::drawArrays(const gl::Data &data,
gl::Error RendererD3D::generateSwizzles(const gl::Data &data, gl::SamplerType type)
{
- gl::Program *program = data.state->getProgram();
+ ProgramD3D *programD3D = GetImplAs<ProgramD3D>(data.state->getProgram());
- size_t samplerRange = program->getUsedSamplerRange(type);
+ unsigned int samplerRange = static_cast<unsigned int>(programD3D->getUsedSamplerRange(type));
- for (size_t i = 0; i < samplerRange; i++)
+ for (unsigned int i = 0; i < samplerRange; i++)
{
- GLenum textureType = program->getSamplerTextureType(type, i);
- GLint textureUnit = program->getSamplerMapping(type, i, *data.caps);
+ GLenum textureType = programD3D->getSamplerTextureType(type, i);
+ GLint textureUnit = programD3D->getSamplerMapping(type, i, *data.caps);
if (textureUnit != -1)
{
gl::Texture *texture = data.state->getSamplerTexture(textureUnit, textureType);
ASSERT(texture);
- if (texture->getSamplerState().swizzleRequired())
+ if (texture->getTextureState().swizzleRequired())
{
gl::Error error = generateSwizzle(texture);
if (error.isError())
@@ -271,51 +323,12 @@ gl::Error RendererD3D::generateSwizzles(const gl::Data &data)
return gl::Error(GL_NO_ERROR);
}
-// Applies the render target surface, depth stencil surface, viewport rectangle and
-// scissor rectangle to the renderer
-gl::Error RendererD3D::applyRenderTarget(const gl::Data &data, GLenum drawMode, bool ignoreViewport)
-{
- const gl::Framebuffer *framebufferObject = data.state->getDrawFramebuffer();
- ASSERT(framebufferObject && framebufferObject->checkStatus(data) == GL_FRAMEBUFFER_COMPLETE);
-
- gl::Error error = applyRenderTarget(framebufferObject);
- if (error.isError())
- {
- return error;
- }
-
- float nearZ, farZ;
- data.state->getDepthRange(&nearZ, &farZ);
- setViewport(data.state->getViewport(), nearZ, farZ, drawMode,
- data.state->getRasterizerState().frontFace, ignoreViewport);
-
- setScissorRectangle(data.state->getScissor(), data.state->isScissorTestEnabled());
-
- return gl::Error(GL_NO_ERROR);
-}
-
-// Applies the fixed-function state (culling, depth test, alpha blending, stenciling, etc) to the Direct3D device
-gl::Error RendererD3D::applyState(const gl::Data &data, GLenum drawMode)
+unsigned int RendererD3D::GetBlendSampleMask(const gl::Data &data, int samples)
{
- const gl::Framebuffer *framebufferObject = data.state->getDrawFramebuffer();
- int samples = framebufferObject->getSamples(data);
-
- gl::RasterizerState rasterizer = data.state->getRasterizerState();
- rasterizer.pointDrawMode = (drawMode == GL_POINTS);
- rasterizer.multiSample = (samples != 0);
-
- gl::Error error = setRasterizerState(rasterizer);
- if (error.isError())
- {
- return error;
- }
-
unsigned int mask = 0;
if (data.state->isSampleCoverageEnabled())
{
- GLclampf coverageValue;
- bool coverageInvert = false;
- data.state->getSampleCoverageParams(&coverageValue, &coverageInvert);
+ GLclampf coverageValue = data.state->getSampleCoverageValue();
if (coverageValue != 0)
{
float threshold = 0.5f;
@@ -332,6 +345,7 @@ gl::Error RendererD3D::applyState(const gl::Data &data, GLenum drawMode)
}
}
+ bool coverageInvert = data.state->getSampleCoverageInvert();
if (coverageInvert)
{
mask = ~mask;
@@ -341,71 +355,58 @@ gl::Error RendererD3D::applyState(const gl::Data &data, GLenum drawMode)
{
mask = 0xFFFFFFFF;
}
- error = setBlendState(framebufferObject, data.state->getBlendState(), data.state->getBlendColor(), mask);
- if (error.isError())
- {
- return error;
- }
-
- error = setDepthStencilState(data.state->getDepthStencilState(), data.state->getStencilRef(),
- data.state->getStencilBackRef(), rasterizer.frontFace == GL_CCW);
- if (error.isError())
- {
- return error;
- }
- return gl::Error(GL_NO_ERROR);
+ return mask;
}
// Applies the shaders and shader constants to the Direct3D device
-gl::Error RendererD3D::applyShaders(const gl::Data &data)
+gl::Error RendererD3D::applyShaders(const gl::Data &data, GLenum drawMode)
{
gl::Program *program = data.state->getProgram();
+ ProgramD3D *programD3D = GetImplAs<ProgramD3D>(program);
+ programD3D->updateCachedInputLayout(*data.state);
- gl::VertexFormat inputLayout[gl::MAX_VERTEX_ATTRIBS];
- gl::VertexFormat::GetInputLayout(inputLayout, program, *data.state);
-
- const gl::Framebuffer *fbo = data.state->getDrawFramebuffer();
-
- gl::Error error = applyShaders(program, inputLayout, fbo, data.state->getRasterizerState().rasterizerDiscard, data.state->isTransformFeedbackActiveUnpaused());
+ gl::Error error = applyShadersImpl(data, drawMode);
if (error.isError())
{
return error;
}
- return program->applyUniforms();
+ return programD3D->applyUniforms(drawMode);
}
// For each Direct3D sampler of either the pixel or vertex stage,
// looks up the corresponding OpenGL texture image unit and texture type,
// and sets the texture and its addressing/filtering state (or NULL when inactive).
+// Sampler mapping needs to be up-to-date on the program object before this is called.
gl::Error RendererD3D::applyTextures(const gl::Data &data, gl::SamplerType shaderType,
- const FramebufferTextureSerialArray &framebufferSerials, size_t framebufferSerialCount)
+ const FramebufferTextureArray &framebufferTextures, size_t framebufferTextureCount)
{
- gl::Program *program = data.state->getProgram();
+ ProgramD3D *programD3D = GetImplAs<ProgramD3D>(data.state->getProgram());
+
+ ASSERT(!programD3D->isSamplerMappingDirty());
- size_t samplerRange = program->getUsedSamplerRange(shaderType);
- for (size_t samplerIndex = 0; samplerIndex < samplerRange; samplerIndex++)
+ unsigned int samplerRange = programD3D->getUsedSamplerRange(shaderType);
+ for (unsigned int samplerIndex = 0; samplerIndex < samplerRange; samplerIndex++)
{
- GLenum textureType = program->getSamplerTextureType(shaderType, samplerIndex);
- GLint textureUnit = program->getSamplerMapping(shaderType, samplerIndex, *data.caps);
+ GLenum textureType = programD3D->getSamplerTextureType(shaderType, samplerIndex);
+ GLint textureUnit = programD3D->getSamplerMapping(shaderType, samplerIndex, *data.caps);
if (textureUnit != -1)
{
gl::Texture *texture = data.state->getSamplerTexture(textureUnit, textureType);
ASSERT(texture);
- gl::SamplerState sampler = texture->getSamplerState();
gl::Sampler *samplerObject = data.state->getSampler(textureUnit);
- if (samplerObject)
- {
- samplerObject->getState(&sampler);
- }
+
+ const gl::SamplerState &samplerState =
+ samplerObject ? samplerObject->getSamplerState() : texture->getSamplerState();
// TODO: std::binary_search may become unavailable using older versions of GCC
- if (texture->isSamplerComplete(sampler, data) &&
- !std::binary_search(framebufferSerials.begin(), framebufferSerials.begin() + framebufferSerialCount, texture->getTextureSerial()))
+ if (texture->isSamplerComplete(samplerState, data) &&
+ !std::binary_search(framebufferTextures.begin(),
+ framebufferTextures.begin() + framebufferTextureCount, texture))
{
- gl::Error error = setSamplerState(shaderType, samplerIndex, texture, sampler);
+ gl::Error error = setSamplerState(shaderType, samplerIndex, texture, samplerState);
if (error.isError())
{
return error;
@@ -421,7 +422,15 @@ gl::Error RendererD3D::applyTextures(const gl::Data &data, gl::SamplerType shade
{
// Texture is not sampler complete or it is in use by the framebuffer. Bind the incomplete texture.
gl::Texture *incompleteTexture = getIncompleteTexture(textureType);
- gl::Error error = setTexture(shaderType, samplerIndex, incompleteTexture);
+
+ gl::Error error = setSamplerState(shaderType, samplerIndex, incompleteTexture,
+ incompleteTexture->getSamplerState());
+ if (error.isError())
+ {
+ return error;
+ }
+
+ error = setTexture(shaderType, samplerIndex, incompleteTexture);
if (error.isError())
{
return error;
@@ -442,30 +451,23 @@ gl::Error RendererD3D::applyTextures(const gl::Data &data, gl::SamplerType shade
// Set all the remaining textures to NULL
size_t samplerCount = (shaderType == gl::SAMPLER_PIXEL) ? data.caps->maxTextureImageUnits
: data.caps->maxVertexTextureImageUnits;
- for (size_t samplerIndex = samplerRange; samplerIndex < samplerCount; samplerIndex++)
- {
- gl::Error error = setTexture(shaderType, samplerIndex, NULL);
- if (error.isError())
- {
- return error;
- }
- }
+ clearTextures(shaderType, samplerRange, samplerCount);
return gl::Error(GL_NO_ERROR);
}
gl::Error RendererD3D::applyTextures(const gl::Data &data)
{
- FramebufferTextureSerialArray framebufferSerials;
- size_t framebufferSerialCount = getBoundFramebufferTextureSerials(data, &framebufferSerials);
+ FramebufferTextureArray framebufferTextures;
+ size_t framebufferSerialCount = getBoundFramebufferTextures(data, &framebufferTextures);
- gl::Error error = applyTextures(data, gl::SAMPLER_VERTEX, framebufferSerials, framebufferSerialCount);
+ gl::Error error = applyTextures(data, gl::SAMPLER_VERTEX, framebufferTextures, framebufferSerialCount);
if (error.isError())
{
return error;
}
- error = applyTextures(data, gl::SAMPLER_PIXEL, framebufferSerials, framebufferSerialCount);
+ error = applyTextures(data, gl::SAMPLER_PIXEL, framebufferTextures, framebufferSerialCount);
if (error.isError())
{
return error;
@@ -476,12 +478,16 @@ gl::Error RendererD3D::applyTextures(const gl::Data &data)
bool RendererD3D::skipDraw(const gl::Data &data, GLenum drawMode)
{
+ const gl::State &state = *data.state;
+
if (drawMode == GL_POINTS)
{
+ bool usesPointSize = GetImplAs<ProgramD3D>(state.getProgram())->usesPointSize();
+
// ProgramBinary assumes non-point rendering if gl_PointSize isn't written,
// which affects varying interpolation. Since the value of gl_PointSize is
// undefined when not written, just skip drawing to avoid unexpected results.
- if (!data.state->getProgram()->usesPointSize() && !data.state->isTransformFeedbackActiveUnpaused())
+ if (!usesPointSize && !state.isTransformFeedbackActiveUnpaused())
{
// This is stictly speaking not an error, but developers should be
// notified of risking undefined behavior.
@@ -492,7 +498,8 @@ bool RendererD3D::skipDraw(const gl::Data &data, GLenum drawMode)
}
else if (gl::IsTriangleMode(drawMode))
{
- if (data.state->getRasterizerState().cullFace && data.state->getRasterizerState().cullMode == GL_FRONT_AND_BACK)
+ if (state.getRasterizerState().cullFace &&
+ state.getRasterizerState().cullMode == GL_FRONT_AND_BACK)
{
return true;
}
@@ -503,43 +510,41 @@ bool RendererD3D::skipDraw(const gl::Data &data, GLenum drawMode)
void RendererD3D::markTransformFeedbackUsage(const gl::Data &data)
{
- for (size_t i = 0; i < data.caps->maxTransformFeedbackSeparateAttributes; i++)
+ const gl::TransformFeedback *transformFeedback = data.state->getCurrentTransformFeedback();
+ for (size_t i = 0; i < transformFeedback->getIndexedBufferCount(); i++)
{
- gl::Buffer *buffer = data.state->getIndexedTransformFeedbackBuffer(i);
- if (buffer)
+ const OffsetBindingPointer<gl::Buffer> &binding = transformFeedback->getIndexedBuffer(i);
+ if (binding.get() != nullptr)
{
- BufferD3D *bufferD3D = GetImplAs<BufferD3D>(buffer);
+ BufferD3D *bufferD3D = GetImplAs<BufferD3D>(binding.get());
bufferD3D->markTransformFeedbackUsage();
}
}
}
-size_t RendererD3D::getBoundFramebufferTextureSerials(const gl::Data &data,
- FramebufferTextureSerialArray *outSerialArray)
+size_t RendererD3D::getBoundFramebufferTextures(const gl::Data &data, FramebufferTextureArray *outTextureArray)
{
- size_t serialCount = 0;
+ size_t textureCount = 0;
const gl::Framebuffer *drawFramebuffer = data.state->getDrawFramebuffer();
- for (unsigned int i = 0; i < data.caps->maxColorAttachments; i++)
+ for (size_t i = 0; i < drawFramebuffer->getNumColorBuffers(); i++)
{
- gl::FramebufferAttachment *attachment = drawFramebuffer->getColorbuffer(i);
+ const gl::FramebufferAttachment *attachment = drawFramebuffer->getColorbuffer(i);
if (attachment && attachment->type() == GL_TEXTURE)
{
- gl::Texture *texture = attachment->getTexture();
- (*outSerialArray)[serialCount++] = texture->getTextureSerial();
+ (*outTextureArray)[textureCount++] = attachment->getTexture();
}
}
- gl::FramebufferAttachment *depthStencilAttachment = drawFramebuffer->getDepthOrStencilbuffer();
+ const gl::FramebufferAttachment *depthStencilAttachment = drawFramebuffer->getDepthOrStencilbuffer();
if (depthStencilAttachment && depthStencilAttachment->type() == GL_TEXTURE)
{
- gl::Texture *depthStencilTexture = depthStencilAttachment->getTexture();
- (*outSerialArray)[serialCount++] = depthStencilTexture->getTextureSerial();
+ (*outTextureArray)[textureCount++] = depthStencilAttachment->getTexture();
}
- std::sort(outSerialArray->begin(), outSerialArray->begin() + serialCount);
+ std::sort(outTextureArray->begin(), outTextureArray->begin() + textureCount);
- return serialCount;
+ return textureCount;
}
gl::Texture *RendererD3D::getIncompleteTexture(GLenum type)
@@ -548,20 +553,26 @@ gl::Texture *RendererD3D::getIncompleteTexture(GLenum type)
{
const GLubyte color[] = { 0, 0, 0, 255 };
const gl::Extents colorSize(1, 1, 1);
- const gl::PixelUnpackState incompleteUnpackState(1, 0);
+ const gl::PixelUnpackState unpack(1, 0);
+ const gl::Box area(0, 0, 0, 1, 1, 1);
- gl::Texture* t = new gl::Texture(createTexture(type), gl::Texture::INCOMPLETE_TEXTURE_ID, type);
+ // Skip the API layer to avoid needing to pass the Context and mess with dirty bits.
+ gl::Texture *t =
+ new gl::Texture(createTexture(type), std::numeric_limits<GLuint>::max(), type);
+ t->setStorage(type, 1, GL_RGBA8, colorSize);
if (type == GL_TEXTURE_CUBE_MAP)
{
for (GLenum face = GL_TEXTURE_CUBE_MAP_POSITIVE_X; face <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z; face++)
{
- t->setImage(face, 0, GL_RGBA, colorSize, GL_RGBA, GL_UNSIGNED_BYTE, incompleteUnpackState, color);
+ t->getImplementation()->setSubImage(face, 0, area, GL_RGBA8, GL_UNSIGNED_BYTE,
+ unpack, color);
}
}
else
{
- t->setImage(type, 0, GL_RGBA, colorSize, GL_RGBA, GL_UNSIGNED_BYTE, incompleteUnpackState, color);
+ t->getImplementation()->setSubImage(type, 0, area, GL_RGBA8, GL_UNSIGNED_BYTE, unpack,
+ color);
}
mIncompleteTextures[type].set(t);
@@ -625,4 +636,68 @@ gl::Error RendererD3D::getScratchMemoryBuffer(size_t requestedSize, MemoryBuffer
return gl::Error(GL_NO_ERROR);
}
+void RendererD3D::insertEventMarker(GLsizei length, const char *marker)
+{
+ std::vector<wchar_t> wcstring (length + 1);
+ size_t convertedChars = 0;
+ errno_t err = mbstowcs_s(&convertedChars, wcstring.data(), length + 1, marker, _TRUNCATE);
+ if (err == 0)
+ {
+ getAnnotator()->setMarker(wcstring.data());
+ }
+}
+
+void RendererD3D::pushGroupMarker(GLsizei length, const char *marker)
+{
+ std::vector<wchar_t> wcstring(length + 1);
+ size_t convertedChars = 0;
+ errno_t err = mbstowcs_s(&convertedChars, wcstring.data(), length + 1, marker, _TRUNCATE);
+ if (err == 0)
+ {
+ getAnnotator()->beginEvent(wcstring.data());
+ }
+}
+
+void RendererD3D::popGroupMarker()
+{
+ getAnnotator()->endEvent();
+}
+
+void RendererD3D::setGPUDisjoint()
+{
+ mDisjoint = true;
+}
+
+GLint RendererD3D::getGPUDisjoint()
+{
+ bool disjoint = mDisjoint;
+
+ // Disjoint flag is cleared when read
+ mDisjoint = false;
+
+ return disjoint;
+}
+
+GLint64 RendererD3D::getTimestamp()
+{
+ // D3D has no way to get an actual timestamp reliably so 0 is returned
+ return 0;
+}
+
+void RendererD3D::onMakeCurrent(const gl::Data &data)
+{
+}
+
+void RendererD3D::initializeDebugAnnotator()
+{
+ createAnnotator();
+ ASSERT(mAnnotator);
+ gl::InitializeDebugAnnotations(mAnnotator);
+}
+
+gl::DebugAnnotator *RendererD3D::getAnnotator()
+{
+ ASSERT(mAnnotator);
+ return mAnnotator;
+}
}
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/RendererD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/RendererD3D.h
index 3de6c20886..f956f037e2 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/RendererD3D.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/RendererD3D.h
@@ -9,10 +9,15 @@
#ifndef LIBANGLE_RENDERER_D3D_RENDERERD3D_H_
#define LIBANGLE_RENDERER_D3D_RENDERERD3D_H_
+#include "common/debug.h"
#include "common/MemoryBuffer.h"
#include "libANGLE/Data.h"
+#include "libANGLE/Device.h"
+#include "libANGLE/formatutils.h"
#include "libANGLE/renderer/Renderer.h"
+#include "libANGLE/renderer/d3d/VertexDataManager.h"
#include "libANGLE/renderer/d3d/formatutilsD3D.h"
+#include "libANGLE/renderer/d3d/WorkaroundsD3D.h"
#include "libANGLE/renderer/d3d/d3d11/NativeWindow.h"
//FIXME(jmadill): std::array is currently prohibited by Chromium style guide
@@ -25,15 +30,21 @@ class ConfigSet;
namespace gl
{
+class DebugAnnotator;
class InfoLog;
-struct LinkedVarying;
class Texture;
+struct LinkedVarying;
}
namespace rx
{
+struct D3DUniform;
+struct D3DVarying;
+class DeviceD3D;
+class EGLImageD3D;
class ImageD3D;
class IndexBuffer;
+class ProgramD3D;
class RenderTargetD3D;
class ShaderExecutableD3D;
class SwapChainD3D;
@@ -45,13 +56,23 @@ enum ShaderType
{
SHADER_VERTEX,
SHADER_PIXEL,
- SHADER_GEOMETRY
+ SHADER_GEOMETRY,
+ SHADER_TYPE_MAX
+};
+
+struct DeviceIdentifier
+{
+ UINT VendorId;
+ UINT DeviceId;
+ UINT SubSysId;
+ UINT Revision;
+ UINT FeatureLevel;
};
enum RendererClass
{
RENDERER_D3D11,
- RENDERER_D3D9,
+ RENDERER_D3D9
};
// Useful for unit testing
@@ -65,8 +86,8 @@ class BufferFactoryD3D
virtual IndexBuffer *createIndexBuffer() = 0;
// TODO(jmadill): add VertexFormatCaps
- virtual VertexConversionType getVertexConversionType(const gl::VertexFormat &vertexFormat) const = 0;
- virtual GLenum getVertexComponentType(const gl::VertexFormat &vertexFormat) const = 0;
+ virtual VertexConversionType getVertexConversionType(gl::VertexFormatType vertexFormatType) const = 0;
+ virtual GLenum getVertexComponentType(gl::VertexFormatType vertexFormatType) const = 0;
};
class RendererD3D : public Renderer, public BufferFactoryD3D
@@ -77,68 +98,93 @@ class RendererD3D : public Renderer, public BufferFactoryD3D
virtual egl::Error initialize() = 0;
- static RendererD3D *makeRendererD3D(Renderer *renderer);
-
virtual egl::ConfigSet generateConfigs() const = 0;
+ virtual void generateDisplayExtensions(egl::DisplayExtensions *outExtensions) const = 0;
- gl::Error drawArrays(const gl::Data &data,
- GLenum mode, GLint first,
- GLsizei count, GLsizei instances) override;
+ gl::Error drawArrays(const gl::Data &data, GLenum mode, GLint first, GLsizei count) override;
+ gl::Error drawArraysInstanced(const gl::Data &data,
+ GLenum mode,
+ GLint first,
+ GLsizei count,
+ GLsizei instanceCount) override;
gl::Error drawElements(const gl::Data &data,
- GLenum mode, GLsizei count, GLenum type,
- const GLvoid *indices, GLsizei instances,
- const RangeUI &indexRange) override;
+ GLenum mode,
+ GLsizei count,
+ GLenum type,
+ const GLvoid *indices,
+ const gl::IndexRange &indexRange) override;
+ gl::Error drawElementsInstanced(const gl::Data &data,
+ GLenum mode,
+ GLsizei count,
+ GLenum type,
+ const GLvoid *indices,
+ GLsizei instances,
+ const gl::IndexRange &indexRange) override;
+ gl::Error drawRangeElements(const gl::Data &data,
+ GLenum mode,
+ GLuint start,
+ GLuint end,
+ GLsizei count,
+ GLenum type,
+ const GLvoid *indices,
+ const gl::IndexRange &indexRange) override;
bool isDeviceLost() const override;
std::string getVendorString() const override;
+ SamplerImpl *createSampler() override;
+
virtual int getMinorShaderModel() const = 0;
virtual std::string getShaderModelSuffix() const = 0;
// Direct3D Specific methods
- virtual GUID getAdapterIdentifier() const = 0;
+ virtual DeviceIdentifier getAdapterIdentifier() const = 0;
- virtual SwapChainD3D *createSwapChain(NativeWindow nativeWindow, HANDLE shareHandle, GLenum backBufferFormat, GLenum depthBufferFormat) = 0;
+ virtual SwapChainD3D *createSwapChain(NativeWindow nativeWindow,
+ HANDLE shareHandle,
+ GLenum backBufferFormat,
+ GLenum depthBufferFormat,
+ EGLint orientation) = 0;
virtual gl::Error generateSwizzle(gl::Texture *texture) = 0;
virtual gl::Error setSamplerState(gl::SamplerType type, int index, gl::Texture *texture, const gl::SamplerState &sampler) = 0;
virtual gl::Error setTexture(gl::SamplerType type, int index, gl::Texture *texture) = 0;
virtual gl::Error setUniformBuffers(const gl::Data &data,
- const GLint vertexUniformBuffers[],
- const GLint fragmentUniformBuffers[]) = 0;
-
- virtual gl::Error setRasterizerState(const gl::RasterizerState &rasterState) = 0;
- virtual gl::Error setBlendState(const gl::Framebuffer *framebuffer, const gl::BlendState &blendState, const gl::ColorF &blendColor,
- unsigned int sampleMask) = 0;
- virtual gl::Error setDepthStencilState(const gl::DepthStencilState &depthStencilState, int stencilRef,
- int stencilBackRef, bool frontFaceCCW) = 0;
+ const std::vector<GLint> &vertexUniformBuffers,
+ const std::vector<GLint> &fragmentUniformBuffers) = 0;
- virtual void setScissorRectangle(const gl::Rectangle &scissor, bool enabled) = 0;
- virtual void setViewport(const gl::Rectangle &viewport, float zNear, float zFar, GLenum drawMode, GLenum frontFace,
- bool ignoreViewport) = 0;
+ virtual gl::Error updateState(const gl::Data &data, GLenum drawMode) = 0;
virtual gl::Error applyRenderTarget(const gl::Framebuffer *frameBuffer) = 0;
- virtual gl::Error applyShaders(gl::Program *program, const gl::VertexFormat inputLayout[], const gl::Framebuffer *framebuffer,
- bool rasterizerDiscard, bool transformFeedbackActive) = 0;
- virtual gl::Error applyUniforms(const ProgramImpl &program, const std::vector<gl::LinkedUniform*> &uniformArray) = 0;
+ virtual gl::Error applyUniforms(const ProgramD3D &programD3D,
+ GLenum drawMode,
+ const std::vector<D3DUniform *> &uniformArray) = 0;
virtual bool applyPrimitiveType(GLenum primitiveType, GLsizei elementCount, bool usesPointSize) = 0;
- virtual gl::Error applyVertexBuffer(const gl::State &state, GLenum mode, GLint first, GLsizei count, GLsizei instances) = 0;
- virtual gl::Error applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo) = 0;
+ virtual gl::Error applyVertexBuffer(const gl::State &state,
+ GLenum mode,
+ GLint first,
+ GLsizei count,
+ GLsizei instances,
+ TranslatedIndexData *indexInfo) = 0;
+ virtual gl::Error applyIndexBuffer(const gl::Data &data,
+ const GLvoid *indices,
+ GLsizei count,
+ GLenum mode,
+ GLenum type,
+ TranslatedIndexData *indexInfo) = 0;
virtual void applyTransformFeedbackBuffers(const gl::State& state) = 0;
- virtual void markAllStateDirty() = 0;
-
virtual unsigned int getReservedVertexUniformVectors() const = 0;
virtual unsigned int getReservedFragmentUniformVectors() const = 0;
virtual unsigned int getReservedVertexUniformBuffers() const = 0;
virtual unsigned int getReservedFragmentUniformBuffers() const = 0;
- virtual bool getShareHandleSupport() const = 0;
- virtual bool getPostSubBufferSupport() const = 0;
virtual int getMajorShaderModel() const = 0;
+ const WorkaroundsD3D &getWorkarounds() const;
+
// Pixel operations
virtual gl::Error copyImage2D(const gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat,
const gl::Offset &destOffset, TextureStorage *storage, GLint level) = 0;
@@ -151,21 +197,31 @@ class RendererD3D : public Renderer, public BufferFactoryD3D
// RenderTarget creation
virtual gl::Error createRenderTarget(int width, int height, GLenum format, GLsizei samples, RenderTargetD3D **outRT) = 0;
+ virtual gl::Error createRenderTargetCopy(RenderTargetD3D *source, RenderTargetD3D **outRT) = 0;
// Shader operations
- virtual gl::Error loadExecutable(const void *function, size_t length, ShaderType type,
- const std::vector<gl::LinkedVarying> &transformFeedbackVaryings,
- bool separatedOutputBuffers, ShaderExecutableD3D **outExecutable) = 0;
- virtual gl::Error compileToExecutable(gl::InfoLog &infoLog, const std::string &shaderHLSL, ShaderType type,
- const std::vector<gl::LinkedVarying> &transformFeedbackVaryings,
- bool separatedOutputBuffers, const D3DCompilerWorkarounds &workarounds,
+ virtual gl::Error loadExecutable(const void *function,
+ size_t length,
+ ShaderType type,
+ const std::vector<D3DVarying> &streamOutVaryings,
+ bool separatedOutputBuffers,
+ ShaderExecutableD3D **outExecutable) = 0;
+ virtual gl::Error compileToExecutable(gl::InfoLog &infoLog,
+ const std::string &shaderHLSL,
+ ShaderType type,
+ const std::vector<D3DVarying> &streamOutVaryings,
+ bool separatedOutputBuffers,
+ const D3DCompilerWorkarounds &workarounds,
ShaderExecutableD3D **outExectuable) = 0;
virtual UniformStorageD3D *createUniformStorage(size_t storageSize) = 0;
// Image operations
virtual ImageD3D *createImage() = 0;
virtual gl::Error generateMipmap(ImageD3D *dest, ImageD3D *source) = 0;
+ virtual gl::Error generateMipmapsUsingD3D(TextureStorage *storage,
+ const gl::TextureState &textureState) = 0;
virtual TextureStorage *createTextureStorage2D(SwapChainD3D *swapChain) = 0;
+ virtual TextureStorage *createTextureStorageEGLImage(EGLImageD3D *eglImage) = 0;
virtual TextureStorage *createTextureStorage2D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels, bool hintLevelZeroOnly) = 0;
virtual TextureStorage *createTextureStorageCube(GLenum internalformat, bool renderTarget, int size, int levels, bool hintLevelZeroOnly) = 0;
virtual TextureStorage *createTextureStorage3D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels) = 0;
@@ -179,61 +235,108 @@ class RendererD3D : public Renderer, public BufferFactoryD3D
// Device lost
void notifyDeviceLost() override;
virtual bool resetDevice() = 0;
-
virtual RendererClass getRendererClass() const = 0;
+ virtual void *getD3DDevice() = 0;
gl::Error getScratchMemoryBuffer(size_t requestedSize, MemoryBuffer **bufferOut);
- protected:
- virtual gl::Error drawArrays(const gl::Data &data, GLenum mode, GLsizei count, GLsizei instances, bool usesPointSize) = 0;
- virtual gl::Error drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices,
- gl::Buffer *elementArrayBuffer, const TranslatedIndexData &indexInfo, GLsizei instances) = 0;
+ // EXT_debug_marker
+ void insertEventMarker(GLsizei length, const char *marker) override;
+ void pushGroupMarker(GLsizei length, const char *marker) override;
+ void popGroupMarker() override;
+
+ void setGPUDisjoint();
+
+ GLint getGPUDisjoint() override;
+ GLint64 getTimestamp() override;
+
+ void onMakeCurrent(const gl::Data &data) override;
+
+ // In D3D11, faster than calling setTexture a jillion times
+ virtual gl::Error clearTextures(gl::SamplerType samplerType, size_t rangeStart, size_t rangeEnd) = 0;
+ virtual egl::Error getEGLDevice(DeviceImpl **device) = 0;
+
+ bool presentPathFastEnabled() const { return mPresentPathFastEnabled; }
+
+ protected:
virtual bool getLUID(LUID *adapterLuid) const = 0;
+ virtual gl::Error applyShadersImpl(const gl::Data &data, GLenum drawMode) = 0;
void cleanup();
+ virtual void createAnnotator() = 0;
+
+ static unsigned int GetBlendSampleMask(const gl::Data &data, int samples);
+ // dirtyPointer is a special value that will make the comparison with any valid pointer fail and force the renderer to re-apply the state.
+
egl::Display *mDisplay;
bool mDeviceLost;
+ void initializeDebugAnnotator();
+ gl::DebugAnnotator *mAnnotator;
+
+ std::vector<TranslatedAttribute> mTranslatedAttribCache;
+
+ bool mPresentPathFastEnabled;
+
private:
+ gl::Error genericDrawArrays(const gl::Data &data,
+ GLenum mode,
+ GLint first,
+ GLsizei count,
+ GLsizei instances);
+
+ gl::Error genericDrawElements(const gl::Data &data,
+ GLenum mode,
+ GLsizei count,
+ GLenum type,
+ const GLvoid *indices,
+ GLsizei instances,
+ const gl::IndexRange &indexRange);
+
+ virtual gl::Error drawArraysImpl(const gl::Data &data,
+ GLenum mode,
+ GLsizei count,
+ GLsizei instances) = 0;
+ virtual gl::Error drawElementsImpl(const gl::Data &data,
+ const TranslatedIndexData &indexInfo,
+ GLenum mode,
+ GLsizei count,
+ GLenum type,
+ const GLvoid *indices,
+ GLsizei instances) = 0;
+
//FIXME(jmadill): std::array is currently prohibited by Chromium style guide
- typedef std::array<unsigned int, gl::IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS> FramebufferTextureSerialArray;
+ typedef std::array<gl::Texture*, gl::IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS> FramebufferTextureArray;
gl::Error generateSwizzles(const gl::Data &data, gl::SamplerType type);
gl::Error generateSwizzles(const gl::Data &data);
- gl::Error applyRenderTarget(const gl::Data &data, GLenum drawMode, bool ignoreViewport);
gl::Error applyState(const gl::Data &data, GLenum drawMode);
- gl::Error applyShaders(const gl::Data &data);
+ gl::Error applyShaders(const gl::Data &data, GLenum drawMode);
gl::Error applyTextures(const gl::Data &data, gl::SamplerType shaderType,
- const FramebufferTextureSerialArray &framebufferSerials, size_t framebufferSerialCount);
+ const FramebufferTextureArray &framebufferTextures, size_t framebufferTextureCount);
gl::Error applyTextures(const gl::Data &data);
bool skipDraw(const gl::Data &data, GLenum drawMode);
void markTransformFeedbackUsage(const gl::Data &data);
- size_t getBoundFramebufferTextureSerials(const gl::Data &data,
- FramebufferTextureSerialArray *outSerialArray);
+ size_t getBoundFramebufferTextures(const gl::Data &data, FramebufferTextureArray *outTextureArray);
gl::Texture *getIncompleteTexture(GLenum type);
+ gl::DebugAnnotator *getAnnotator();
+
+ virtual WorkaroundsD3D generateWorkarounds() const = 0;
+
gl::TextureMap mIncompleteTextures;
MemoryBuffer mScratchMemoryBuffer;
unsigned int mScratchMemoryBufferResetCounter;
-};
-struct dx_VertexConstants
-{
- float depthRange[4];
- float viewAdjust[4];
- float viewCoords[4];
-};
+ mutable bool mWorkaroundsInitialized;
+ mutable WorkaroundsD3D mWorkarounds;
-struct dx_PixelConstants
-{
- float depthRange[4];
- float viewCoords[4];
- float depthFront[4];
+ bool mDisjoint;
};
}
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/SamplerD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/SamplerD3D.h
new file mode 100644
index 0000000000..7aabdc8132
--- /dev/null
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/SamplerD3D.h
@@ -0,0 +1,25 @@
+//
+// Copyright 2014 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// SamplerD3D.h: Defines the rx::SamplerD3D class, an implementation of SamplerImpl.
+
+#ifndef LIBANGLE_RENDERER_D3D_SAMPLERD3D_H_
+#define LIBANGLE_RENDERER_D3D_SAMPLERD3D_H_
+
+#include "libANGLE/renderer/SamplerImpl.h"
+
+namespace rx
+{
+
+class SamplerD3D : public SamplerImpl
+{
+ public:
+ SamplerD3D() {}
+ ~SamplerD3D() override {}
+};
+}
+
+#endif // LIBANGLE_RENDERER_D3D_SAMPLERD3D_H_
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/ShaderD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/ShaderD3D.cpp
index 7d522a95d4..1ecbfb7410 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/ShaderD3D.cpp
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/ShaderD3D.cpp
@@ -6,14 +6,13 @@
// ShaderD3D.cpp: Defines the rx::ShaderD3D class which implements rx::ShaderImpl.
-#include "libANGLE/Shader.h"
-#include "libANGLE/Compiler.h"
-#include "libANGLE/renderer/d3d/RendererD3D.h"
#include "libANGLE/renderer/d3d/ShaderD3D.h"
-#include "libANGLE/renderer/d3d/CompilerD3D.h"
-#include "libANGLE/features.h"
#include "common/utilities.h"
+#include "libANGLE/Compiler.h"
+#include "libANGLE/Shader.h"
+#include "libANGLE/features.h"
+#include "libANGLE/renderer/d3d/RendererD3D.h"
// Definitions local to the translation unit
namespace
@@ -23,51 +22,24 @@ const char *GetShaderTypeString(GLenum type)
{
switch (type)
{
- case GL_VERTEX_SHADER:
- return "VERTEX";
+ case GL_VERTEX_SHADER:
+ return "VERTEX";
- case GL_FRAGMENT_SHADER:
- return "FRAGMENT";
+ case GL_FRAGMENT_SHADER:
+ return "FRAGMENT";
- default:
- UNREACHABLE();
- return "";
+ default:
+ UNREACHABLE();
+ return "";
}
}
-}
+} // anonymous namespace
namespace rx
{
-template <typename VarT>
-void FilterInactiveVariables(std::vector<VarT> *variableList)
-{
- ASSERT(variableList);
-
- for (size_t varIndex = 0; varIndex < variableList->size();)
- {
- if (!(*variableList)[varIndex].staticUse)
- {
- variableList->erase(variableList->begin() + varIndex);
- }
- else
- {
- varIndex++;
- }
- }
-}
-
-template <typename VarT>
-const std::vector<VarT> *GetShaderVariables(const std::vector<VarT> *variableList)
-{
- ASSERT(variableList);
- return variableList;
-}
-
-ShaderD3D::ShaderD3D(GLenum type)
- : mShaderType(type),
- mShaderVersion(100)
+ShaderD3D::ShaderD3D(const gl::Shader::Data &data) : ShaderImpl(data)
{
uncompile();
}
@@ -76,58 +48,10 @@ ShaderD3D::~ShaderD3D()
{
}
-ShaderD3D *ShaderD3D::makeShaderD3D(ShaderImpl *impl)
-{
- ASSERT(HAS_DYNAMIC_TYPE(ShaderD3D*, impl));
- return static_cast<ShaderD3D*>(impl);
-}
-
-const ShaderD3D *ShaderD3D::makeShaderD3D(const ShaderImpl *impl)
-{
- ASSERT(HAS_DYNAMIC_TYPE(const ShaderD3D*, impl));
- return static_cast<const ShaderD3D*>(impl);
-}
-
std::string ShaderD3D::getDebugInfo() const
{
- return mDebugInfo + std::string("\n// ") + GetShaderTypeString(mShaderType) + " SHADER END\n";
-}
-
-
-void ShaderD3D::parseVaryings(ShHandle compiler)
-{
- if (!mTranslatedSource.empty())
- {
- const std::vector<sh::Varying> *varyings = ShGetVaryings(compiler);
- ASSERT(varyings);
-
- for (size_t varyingIndex = 0; varyingIndex < varyings->size(); varyingIndex++)
- {
- mVaryings.push_back(gl::PackedVarying((*varyings)[varyingIndex]));
- }
-
- mUsesMultipleRenderTargets = mTranslatedSource.find("GL_USES_MRT") != std::string::npos;
- mUsesFragColor = mTranslatedSource.find("GL_USES_FRAG_COLOR") != std::string::npos;
- mUsesFragData = mTranslatedSource.find("GL_USES_FRAG_DATA") != std::string::npos;
- mUsesFragCoord = mTranslatedSource.find("GL_USES_FRAG_COORD") != std::string::npos;
- mUsesFrontFacing = mTranslatedSource.find("GL_USES_FRONT_FACING") != std::string::npos;
- mUsesPointSize = mTranslatedSource.find("GL_USES_POINT_SIZE") != std::string::npos;
- mUsesPointCoord = mTranslatedSource.find("GL_USES_POINT_COORD") != std::string::npos;
- mUsesDepthRange = mTranslatedSource.find("GL_USES_DEPTH_RANGE") != std::string::npos;
- mUsesFragDepth = mTranslatedSource.find("GL_USES_FRAG_DEPTH") != std::string::npos;
- mUsesDiscardRewriting = mTranslatedSource.find("ANGLE_USES_DISCARD_REWRITING") != std::string::npos;
- mUsesNestedBreak = mTranslatedSource.find("ANGLE_USES_NESTED_BREAK") != std::string::npos;
- mUsesDeferredInit = mTranslatedSource.find("ANGLE_USES_DEFERRED_INIT") != std::string::npos;
- mRequiresIEEEStrictCompiling = mTranslatedSource.find("ANGLE_REQUIRES_IEEE_STRICT_COMPILING") != std::string::npos;
- }
-}
-
-void ShaderD3D::resetVaryingsRegisterAssignment()
-{
- for (size_t varyingIndex = 0; varyingIndex < mVaryings.size(); varyingIndex++)
- {
- mVaryings[varyingIndex].resetRegisterAssignment();
- }
+ return mDebugInfo + std::string("\n// ") + GetShaderTypeString(mData.getShaderType()) +
+ " SHADER END\n";
}
// initialize/clean up previous state
@@ -135,8 +59,6 @@ void ShaderD3D::uncompile()
{
// set by compileToHLSL
mCompilerOutputType = SH_ESSL_OUTPUT;
- mTranslatedSource.clear();
- mInfoLog.clear();
mUsesMultipleRenderTargets = false;
mUsesFragColor = false;
@@ -147,125 +69,14 @@ void ShaderD3D::uncompile()
mUsesPointCoord = false;
mUsesDepthRange = false;
mUsesFragDepth = false;
- mShaderVersion = 100;
mUsesDiscardRewriting = false;
mUsesNestedBreak = false;
mUsesDeferredInit = false;
mRequiresIEEEStrictCompiling = false;
- mVaryings.clear();
- mUniforms.clear();
- mInterfaceBlocks.clear();
- mActiveAttributes.clear();
- mActiveOutputVariables.clear();
mDebugInfo.clear();
}
-void ShaderD3D::compileToHLSL(ShHandle compiler, const std::string &source)
-{
- int compileOptions = (SH_OBJECT_CODE | SH_VARIABLES);
- std::string sourcePath;
-
-#if !defined (ANGLE_ENABLE_WINDOWS_STORE)
- if (gl::DebugAnnotationsActive())
- {
- sourcePath = getTempPath();
- writeFile(sourcePath.c_str(), source.c_str(), source.length());
- compileOptions |= SH_LINE_DIRECTIVES;
- }
-#endif
-
- int result;
- if (sourcePath.empty())
- {
- const char* sourceStrings[] =
- {
- source.c_str(),
- };
-
- result = ShCompile(compiler, sourceStrings, ArraySize(sourceStrings), compileOptions);
- }
- else
- {
- const char* sourceStrings[] =
- {
- sourcePath.c_str(),
- source.c_str(),
- };
-
- result = ShCompile(compiler, sourceStrings, ArraySize(sourceStrings), compileOptions | SH_SOURCE_PATH);
- }
-
- mShaderVersion = ShGetShaderVersion(compiler);
-
- if (result)
- {
- mTranslatedSource = ShGetObjectCode(compiler);
-
-#ifdef _DEBUG
- // Prefix hlsl shader with commented out glsl shader
- // Useful in diagnostics tools like pix which capture the hlsl shaders
- std::ostringstream hlslStream;
- hlslStream << "// GLSL\n";
- hlslStream << "//\n";
-
- size_t curPos = 0;
- while (curPos != std::string::npos)
- {
- size_t nextLine = source.find("\n", curPos);
- size_t len = (nextLine == std::string::npos) ? std::string::npos : (nextLine - curPos + 1);
-
- hlslStream << "// " << source.substr(curPos, len);
-
- curPos = (nextLine == std::string::npos) ? std::string::npos : (nextLine + 1);
- }
- hlslStream << "\n\n";
- hlslStream << mTranslatedSource;
- mTranslatedSource = hlslStream.str();
-#endif
-
- mUniforms = *GetShaderVariables(ShGetUniforms(compiler));
-
- for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
- {
- const sh::Uniform &uniform = mUniforms[uniformIndex];
-
- if (uniform.staticUse)
- {
- unsigned int index = static_cast<unsigned int>(-1);
- bool getUniformRegisterResult = ShGetUniformRegister(compiler, uniform.name, &index);
- UNUSED_ASSERTION_VARIABLE(getUniformRegisterResult);
- ASSERT(getUniformRegisterResult);
-
- mUniformRegisterMap[uniform.name] = index;
- }
- }
-
- mInterfaceBlocks = *GetShaderVariables(ShGetInterfaceBlocks(compiler));
-
- for (size_t blockIndex = 0; blockIndex < mInterfaceBlocks.size(); blockIndex++)
- {
- const sh::InterfaceBlock &interfaceBlock = mInterfaceBlocks[blockIndex];
-
- if (interfaceBlock.staticUse)
- {
- unsigned int index = static_cast<unsigned int>(-1);
- bool blockRegisterResult = ShGetInterfaceBlockRegister(compiler, interfaceBlock.name, &index);
- UNUSED_ASSERTION_VARIABLE(blockRegisterResult);
- ASSERT(blockRegisterResult);
-
- mInterfaceBlockRegisterMap[interfaceBlock.name] = index;
- }
- }
- }
- else
- {
- mInfoLog = ShGetInfoLog(compiler);
-
- TRACE("\n%s", mInfoLog.c_str());
- }
-}
-
void ShaderD3D::generateWorkarounds(D3DCompilerWorkarounds *workarounds) const
{
if (mUsesDiscardRewriting)
@@ -289,28 +100,6 @@ void ShaderD3D::generateWorkarounds(D3DCompilerWorkarounds *workarounds) const
}
}
-// true if varying x has a higher priority in packing than y
-bool ShaderD3D::compareVarying(const gl::PackedVarying &x, const gl::PackedVarying &y)
-{
- if (x.type == y.type)
- {
- return x.arraySize > y.arraySize;
- }
-
- // Special case for handling structs: we sort these to the end of the list
- if (x.type == GL_STRUCT_ANGLEX)
- {
- return false;
- }
-
- if (y.type == GL_STRUCT_ANGLEX)
- {
- return true;
- }
-
- return gl::VariableSortOrder(x.type) < gl::VariableSortOrder(y.type);
-}
-
unsigned int ShaderD3D::getUniformRegister(const std::string &uniformName) const
{
ASSERT(mUniformRegisterMap.count(uniformName) > 0);
@@ -323,66 +112,92 @@ unsigned int ShaderD3D::getInterfaceBlockRegister(const std::string &blockName)
return mInterfaceBlockRegisterMap.find(blockName)->second;
}
-GLenum ShaderD3D::getShaderType() const
-{
- return mShaderType;
-}
-
ShShaderOutput ShaderD3D::getCompilerOutputType() const
{
return mCompilerOutputType;
}
-bool ShaderD3D::compile(gl::Compiler *compiler, const std::string &source)
+int ShaderD3D::prepareSourceAndReturnOptions(std::stringstream *shaderSourceStream,
+ std::string *sourcePath)
{
uncompile();
- CompilerD3D *compilerD3D = CompilerD3D::makeCompilerD3D(compiler->getImplementation());
- ShHandle compilerHandle = compilerD3D->getCompilerHandle(mShaderType);
+ int additionalOptions = 0;
- mCompilerOutputType = ShGetShaderOutputType(compilerHandle);
+ const std::string &source = mData.getSource();
- compileToHLSL(compilerHandle, source);
-
- if (mShaderType == GL_VERTEX_SHADER)
+#if !defined(ANGLE_ENABLE_WINDOWS_STORE)
+ if (gl::DebugAnnotationsActive())
{
- parseAttributes(compilerHandle);
+ *sourcePath = getTempPath();
+ writeFile(sourcePath->c_str(), source.c_str(), source.length());
+ additionalOptions |= SH_LINE_DIRECTIVES | SH_SOURCE_PATH;
}
+#endif
+
+ *shaderSourceStream << source;
+ return additionalOptions;
+}
+
+bool ShaderD3D::postTranslateCompile(gl::Compiler *compiler, std::string *infoLog)
+{
+ // TODO(jmadill): We shouldn't need to cache this.
+ mCompilerOutputType = compiler->getShaderOutputType();
- parseVaryings(compilerHandle);
+ const std::string &translatedSource = mData.getTranslatedSource();
- if (mShaderType == GL_FRAGMENT_SHADER)
- {
- std::sort(mVaryings.begin(), mVaryings.end(), compareVarying);
+ mUsesMultipleRenderTargets = translatedSource.find("GL_USES_MRT") != std::string::npos;
+ mUsesFragColor = translatedSource.find("GL_USES_FRAG_COLOR") != std::string::npos;
+ mUsesFragData = translatedSource.find("GL_USES_FRAG_DATA") != std::string::npos;
+ mUsesFragCoord = translatedSource.find("GL_USES_FRAG_COORD") != std::string::npos;
+ mUsesFrontFacing = translatedSource.find("GL_USES_FRONT_FACING") != std::string::npos;
+ mUsesPointSize = translatedSource.find("GL_USES_POINT_SIZE") != std::string::npos;
+ mUsesPointCoord = translatedSource.find("GL_USES_POINT_COORD") != std::string::npos;
+ mUsesDepthRange = translatedSource.find("GL_USES_DEPTH_RANGE") != std::string::npos;
+ mUsesFragDepth = translatedSource.find("GL_USES_FRAG_DEPTH") != std::string::npos;
+ mUsesDiscardRewriting =
+ translatedSource.find("ANGLE_USES_DISCARD_REWRITING") != std::string::npos;
+ mUsesNestedBreak = translatedSource.find("ANGLE_USES_NESTED_BREAK") != std::string::npos;
+ mUsesDeferredInit = translatedSource.find("ANGLE_USES_DEFERRED_INIT") != std::string::npos;
+ mRequiresIEEEStrictCompiling =
+ translatedSource.find("ANGLE_REQUIRES_IEEE_STRICT_COMPILING") != std::string::npos;
- const std::string &hlsl = getTranslatedSource();
- if (!hlsl.empty())
+ ShHandle compilerHandle = compiler->getCompilerHandle(mData.getShaderType());
+
+ for (const sh::Uniform &uniform : mData.getUniforms())
+ {
+ if (uniform.staticUse && !uniform.isBuiltIn())
{
- mActiveOutputVariables = *GetShaderVariables(ShGetOutputVariables(compilerHandle));
- FilterInactiveVariables(&mActiveOutputVariables);
+ unsigned int index = static_cast<unsigned int>(-1);
+ bool getUniformRegisterResult =
+ ShGetUniformRegister(compilerHandle, uniform.name, &index);
+ UNUSED_ASSERTION_VARIABLE(getUniformRegisterResult);
+ ASSERT(getUniformRegisterResult);
+
+ mUniformRegisterMap[uniform.name] = index;
}
}
-#if ANGLE_SHADER_DEBUG_INFO == ANGLE_ENABLED
- mDebugInfo += std::string("// ") + GetShaderTypeString(mShaderType) + " SHADER BEGIN\n";
- mDebugInfo += "\n// GLSL BEGIN\n\n" + source + "\n\n// GLSL END\n\n\n";
- mDebugInfo += "// INITIAL HLSL BEGIN\n\n" + getTranslatedSource() + "\n// INITIAL HLSL END\n\n\n";
- // Successive steps will append more info
-#else
- mDebugInfo += getTranslatedSource();
-#endif
-
- return !getTranslatedSource().empty();
-}
-
-void ShaderD3D::parseAttributes(ShHandle compiler)
-{
- const std::string &hlsl = getTranslatedSource();
- if (!hlsl.empty())
+ for (const sh::InterfaceBlock &interfaceBlock : mData.getInterfaceBlocks())
{
- mActiveAttributes = *GetShaderVariables(ShGetAttributes(compiler));
- FilterInactiveVariables(&mActiveAttributes);
+ if (interfaceBlock.staticUse)
+ {
+ unsigned int index = static_cast<unsigned int>(-1);
+ bool blockRegisterResult =
+ ShGetInterfaceBlockRegister(compilerHandle, interfaceBlock.name, &index);
+ UNUSED_ASSERTION_VARIABLE(blockRegisterResult);
+ ASSERT(blockRegisterResult);
+
+ mInterfaceBlockRegisterMap[interfaceBlock.name] = index;
+ }
}
-}
+ mDebugInfo +=
+ std::string("// ") + GetShaderTypeString(mData.getShaderType()) + " SHADER BEGIN\n";
+ mDebugInfo += "\n// GLSL BEGIN\n\n" + mData.getSource() + "\n\n// GLSL END\n\n\n";
+ mDebugInfo += "// INITIAL HLSL BEGIN\n\n" + translatedSource + "\n// INITIAL HLSL END\n\n\n";
+ // Successive steps will append more info
+ return true;
}
+
+} // namespace rx
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/ShaderD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/ShaderD3D.h
index d0237b5985..47a73dc27b 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/ShaderD3D.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/ShaderD3D.h
@@ -10,8 +10,6 @@
#define LIBANGLE_RENDERER_D3D_SHADERD3D_H_
#include "libANGLE/renderer/ShaderImpl.h"
-#include "libANGLE/renderer/Workarounds.h"
-#include "libANGLE/Shader.h"
#include <map>
@@ -19,51 +17,42 @@ namespace rx
{
class DynamicHLSL;
class RendererD3D;
+struct D3DCompilerWorkarounds;
class ShaderD3D : public ShaderImpl
{
- friend class DynamicHLSL;
-
public:
- ShaderD3D(GLenum type);
+ ShaderD3D(const gl::Shader::Data &data);
virtual ~ShaderD3D();
- static ShaderD3D *makeShaderD3D(ShaderImpl *impl);
- static const ShaderD3D *makeShaderD3D(const ShaderImpl *impl);
-
// ShaderImpl implementation
- virtual std::string getDebugInfo() const;
+ int prepareSourceAndReturnOptions(std::stringstream *sourceStream,
+ std::string *sourcePath) override;
+ bool postTranslateCompile(gl::Compiler *compiler, std::string *infoLog) override;
+ std::string getDebugInfo() const override;
// D3D-specific methods
- virtual void uncompile();
- void resetVaryingsRegisterAssignment();
+ void uncompile();
unsigned int getUniformRegister(const std::string &uniformName) const;
unsigned int getInterfaceBlockRegister(const std::string &blockName) const;
- void appendDebugInfo(const std::string &info) { mDebugInfo += info; }
+ void appendDebugInfo(const std::string &info) const { mDebugInfo += info; }
void generateWorkarounds(D3DCompilerWorkarounds *workarounds) const;
- int getShaderVersion() const { return mShaderVersion; }
- bool usesDepthRange() const { return mUsesDepthRange; }
+
+ bool usesMultipleRenderTargets() const { return mUsesMultipleRenderTargets; }
+ bool usesFragColor() const { return mUsesFragColor; }
+ bool usesFragData() const { return mUsesFragData; }
+ bool usesFragCoord() const { return mUsesFragCoord; }
+ bool usesFrontFacing() const { return mUsesFrontFacing; }
bool usesPointSize() const { return mUsesPointSize; }
+ bool usesPointCoord() const { return mUsesPointCoord; }
+ bool usesDepthRange() const { return mUsesDepthRange; }
+ bool usesFragDepth() const { return mUsesFragDepth; }
bool usesDeferredInit() const { return mUsesDeferredInit; }
- GLenum getShaderType() const;
ShShaderOutput getCompilerOutputType() const;
- virtual bool compile(gl::Compiler *compiler, const std::string &source);
-
private:
- void compileToHLSL(ShHandle compiler, const std::string &source);
- void parseVaryings(ShHandle compiler);
-
- void parseAttributes(ShHandle compiler);
-
- static bool compareVarying(const gl::PackedVarying &x, const gl::PackedVarying &y);
-
- GLenum mShaderType;
-
- int mShaderVersion;
-
bool mUsesMultipleRenderTargets;
bool mUsesFragColor;
bool mUsesFragData;
@@ -79,11 +68,10 @@ class ShaderD3D : public ShaderImpl
bool mRequiresIEEEStrictCompiling;
ShShaderOutput mCompilerOutputType;
- std::string mDebugInfo;
+ mutable std::string mDebugInfo;
std::map<std::string, unsigned int> mUniformRegisterMap;
std::map<std::string, unsigned int> mInterfaceBlockRegisterMap;
};
-
}
-#endif // LIBANGLE_RENDERER_D3D_SHADERD3D_H_
+#endif // LIBANGLE_RENDERER_D3D_SHADERD3D_H_
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/SurfaceD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/SurfaceD3D.cpp
index 84515f4c6c..3d27548504 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/SurfaceD3D.cpp
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/SurfaceD3D.cpp
@@ -11,6 +11,7 @@
#include "libANGLE/Display.h"
#include "libANGLE/Surface.h"
#include "libANGLE/renderer/d3d/RendererD3D.h"
+#include "libANGLE/renderer/d3d/RenderTargetD3D.h"
#include "libANGLE/renderer/d3d/SwapChainD3D.h"
#include <tchar.h>
@@ -23,38 +24,53 @@ namespace rx
SurfaceD3D *SurfaceD3D::createOffscreen(RendererD3D *renderer, egl::Display *display, const egl::Config *config, EGLClientBuffer shareHandle,
EGLint width, EGLint height)
{
- return new SurfaceD3D(renderer, display, config, width, height, EGL_TRUE, shareHandle, NULL);
+ return new SurfaceD3D(renderer, display, config, width, height, EGL_TRUE, 0, EGL_FALSE,
+ shareHandle, NULL);
}
-SurfaceD3D *SurfaceD3D::createFromWindow(RendererD3D *renderer, egl::Display *display, const egl::Config *config, EGLNativeWindowType window,
- EGLint fixedSize, EGLint width, EGLint height)
+SurfaceD3D *SurfaceD3D::createFromWindow(RendererD3D *renderer,
+ egl::Display *display,
+ const egl::Config *config,
+ EGLNativeWindowType window,
+ EGLint fixedSize,
+ EGLint directComposition,
+ EGLint width,
+ EGLint height,
+ EGLint orientation)
{
- return new SurfaceD3D(renderer, display, config, width, height, fixedSize, static_cast<EGLClientBuffer>(0), window);
+ return new SurfaceD3D(renderer, display, config, width, height, fixedSize, orientation,
+ directComposition, static_cast<EGLClientBuffer>(0), window);
}
-SurfaceD3D::SurfaceD3D(RendererD3D *renderer, egl::Display *display, const egl::Config *config, EGLint width, EGLint height, EGLint fixedSize,
- EGLClientBuffer shareHandle, EGLNativeWindowType window)
+SurfaceD3D::SurfaceD3D(RendererD3D *renderer,
+ egl::Display *display,
+ const egl::Config *config,
+ EGLint width,
+ EGLint height,
+ EGLint fixedSize,
+ EGLint orientation,
+ EGLint directComposition,
+ EGLClientBuffer shareHandle,
+ EGLNativeWindowType window)
: SurfaceImpl(),
mRenderer(renderer),
mDisplay(display),
mFixedSize(fixedSize == EGL_TRUE),
+ mOrientation(orientation),
mRenderTargetFormat(config->renderTargetFormat),
mDepthStencilFormat(config->depthStencilFormat),
mSwapChain(nullptr),
mSwapIntervalDirty(true),
- mWindowSubclassed(false),
- mNativeWindow(window),
+ mNativeWindow(window, config, directComposition == EGL_TRUE),
mWidth(width),
mHeight(height),
mSwapInterval(1),
- mShareHandle(reinterpret_cast<HANDLE*>(shareHandle))
+ mShareHandle(reinterpret_cast<HANDLE *>(shareHandle))
{
- subclassWindow();
}
SurfaceD3D::~SurfaceD3D()
{
- unsubclassWindow();
releaseSwapChain();
}
@@ -82,7 +98,12 @@ egl::Error SurfaceD3D::initialize()
return egl::Error(EGL_SUCCESS);
}
-egl::Error SurfaceD3D::bindTexImage(EGLint)
+FramebufferImpl *SurfaceD3D::createDefaultFramebuffer(const gl::Framebuffer::Data &data)
+{
+ return mRenderer->createFramebuffer(data);
+}
+
+egl::Error SurfaceD3D::bindTexImage(gl::Texture *, EGLint)
{
return egl::Error(EGL_SUCCESS);
}
@@ -119,7 +140,8 @@ egl::Error SurfaceD3D::resetSwapChain()
height = mHeight;
}
- mSwapChain = mRenderer->createSwapChain(mNativeWindow, mShareHandle, mRenderTargetFormat, mDepthStencilFormat);
+ mSwapChain = mRenderer->createSwapChain(mNativeWindow, mShareHandle, mRenderTargetFormat,
+ mDepthStencilFormat, mOrientation);
if (!mSwapChain)
{
return egl::Error(EGL_BAD_ALLOC);
@@ -201,22 +223,19 @@ egl::Error SurfaceD3D::swapRect(EGLint x, EGLint y, EGLint width, EGLint height)
}
#endif
- if (width == 0 || height == 0)
+ if (width != 0 && height != 0)
{
- checkForOutOfDateSwapChain();
- return egl::Error(EGL_SUCCESS);
- }
+ EGLint status = mSwapChain->swapRect(x, y, width, height);
- EGLint status = mSwapChain->swapRect(x, y, width, height);
-
- if (status == EGL_CONTEXT_LOST)
- {
- mRenderer->notifyDeviceLost();
- return egl::Error(status);
- }
- else if (status != EGL_SUCCESS)
- {
- return egl::Error(status);
+ if (status == EGL_CONTEXT_LOST)
+ {
+ mRenderer->notifyDeviceLost();
+ return egl::Error(status);
+ }
+ else if (status != EGL_SUCCESS)
+ {
+ return egl::Error(status);
+ }
}
checkForOutOfDateSwapChain();
@@ -224,90 +243,6 @@ egl::Error SurfaceD3D::swapRect(EGLint x, EGLint y, EGLint width, EGLint height)
return egl::Error(EGL_SUCCESS);
}
-#if !defined(ANGLE_ENABLE_WINDOWS_STORE)
-#define kSurfaceProperty _TEXT("Egl::SurfaceOwner")
-#define kParentWndProc _TEXT("Egl::SurfaceParentWndProc")
-
-static LRESULT CALLBACK SurfaceWindowProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
-{
- if (message == WM_SIZE)
- {
- SurfaceD3D* surf = reinterpret_cast<SurfaceD3D*>(GetProp(hwnd, kSurfaceProperty));
- if(surf)
- {
- surf->checkForOutOfDateSwapChain();
- }
- }
- WNDPROC prevWndFunc = reinterpret_cast<WNDPROC >(GetProp(hwnd, kParentWndProc));
- return CallWindowProc(prevWndFunc, hwnd, message, wparam, lparam);
-}
-#endif
-
-void SurfaceD3D::subclassWindow()
-{
-#if !defined(ANGLE_ENABLE_WINDOWS_STORE)
- HWND window = mNativeWindow.getNativeWindow();
- if (!window)
- {
- return;
- }
-
- DWORD processId;
- DWORD threadId = GetWindowThreadProcessId(window, &processId);
- if (processId != GetCurrentProcessId() || threadId != GetCurrentThreadId())
- {
- return;
- }
-
- SetLastError(0);
- LONG_PTR oldWndProc = SetWindowLongPtr(window, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(SurfaceWindowProc));
- if(oldWndProc == 0 && GetLastError() != ERROR_SUCCESS)
- {
- mWindowSubclassed = false;
- return;
- }
-
- SetProp(window, kSurfaceProperty, reinterpret_cast<HANDLE>(this));
- SetProp(window, kParentWndProc, reinterpret_cast<HANDLE>(oldWndProc));
- mWindowSubclassed = true;
-#endif
-}
-
-void SurfaceD3D::unsubclassWindow()
-{
- if (!mWindowSubclassed)
- {
- return;
- }
-
-#if !defined(ANGLE_ENABLE_WINDOWS_STORE)
- HWND window = mNativeWindow.getNativeWindow();
- if (!window)
- {
- return;
- }
-
- // un-subclass
- LONG_PTR parentWndFunc = reinterpret_cast<LONG_PTR>(GetProp(window, kParentWndProc));
-
- // Check the windowproc is still SurfaceWindowProc.
- // If this assert fails, then it is likely the application has subclassed the
- // hwnd as well and did not unsubclass before destroying its EGL context. The
- // application should be modified to either subclass before initializing the
- // EGL context, or to unsubclass before destroying the EGL context.
- if(parentWndFunc)
- {
- LONG_PTR prevWndFunc = SetWindowLongPtr(window, GWLP_WNDPROC, parentWndFunc);
- UNUSED_ASSERTION_VARIABLE(prevWndFunc);
- ASSERT(prevWndFunc == reinterpret_cast<LONG_PTR>(SurfaceWindowProc));
- }
-
- RemoveProp(window, kSurfaceProperty);
- RemoveProp(window, kParentWndProc);
-#endif
- mWindowSubclassed = false;
-}
-
bool SurfaceD3D::checkForOutOfDateSwapChain()
{
RECT client;
@@ -386,14 +321,42 @@ EGLint SurfaceD3D::isPostSubBufferSupported() const
return EGL_TRUE;
}
+EGLint SurfaceD3D::getSwapBehavior() const
+{
+ return EGL_BUFFER_PRESERVED;
+}
+
egl::Error SurfaceD3D::querySurfacePointerANGLE(EGLint attribute, void **value)
{
- ASSERT(attribute == EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE || attribute == EGL_DEVICE_EXT);
if (attribute == EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE)
+ {
*value = mSwapChain->getShareHandle();
+ }
+ else if (attribute == EGL_DXGI_KEYED_MUTEX_ANGLE)
+ {
+ *value = mSwapChain->getKeyedMutex();
+ }
else if (attribute == EGL_DEVICE_EXT)
+ {
*value = mSwapChain->getDevice();
+ }
+ else UNREACHABLE();
+
return egl::Error(EGL_SUCCESS);
}
+gl::Error SurfaceD3D::getAttachmentRenderTarget(const gl::FramebufferAttachment::Target &target,
+ FramebufferAttachmentRenderTarget **rtOut)
+{
+ if (target.binding() == GL_BACK)
+ {
+ *rtOut = mSwapChain->getColorRenderTarget();
+ }
+ else
+ {
+ *rtOut = mSwapChain->getDepthStencilRenderTarget();
+ }
+ return gl::Error(GL_NO_ERROR);
+}
+
}
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/SurfaceD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/SurfaceD3D.h
index 070b7cdbc4..b925bfc8cc 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/SurfaceD3D.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/SurfaceD3D.h
@@ -25,19 +25,27 @@ class RendererD3D;
class SurfaceD3D : public SurfaceImpl
{
public:
- static SurfaceD3D *createFromWindow(RendererD3D *renderer, egl::Display *display, const egl::Config *config,
- EGLNativeWindowType window, EGLint fixedSize, EGLint width, EGLint height);
+ static SurfaceD3D *createFromWindow(RendererD3D *renderer,
+ egl::Display *display,
+ const egl::Config *config,
+ EGLNativeWindowType window,
+ EGLint fixedSize,
+ EGLint directComposition,
+ EGLint width,
+ EGLint height,
+ EGLint orientation);
static SurfaceD3D *createOffscreen(RendererD3D *renderer, egl::Display *display, const egl::Config *config,
EGLClientBuffer shareHandle, EGLint width, EGLint height);
~SurfaceD3D() override;
void releaseSwapChain();
egl::Error initialize() override;
+ FramebufferImpl *createDefaultFramebuffer(const gl::Framebuffer::Data &data) override;
egl::Error swap() override;
egl::Error postSubBuffer(EGLint x, EGLint y, EGLint width, EGLint height) override;
egl::Error querySurfacePointerANGLE(EGLint attribute, void **value) override;
- egl::Error bindTexImage(EGLint buffer) override;
+ egl::Error bindTexImage(gl::Texture *texture, EGLint buffer) override;
egl::Error releaseTexImage(EGLint buffer) override;
void setSwapInterval(EGLint interval) override;
@@ -45,6 +53,7 @@ class SurfaceD3D : public SurfaceImpl
EGLint getHeight() const override;
EGLint isPostSubBufferSupported() const override;
+ EGLint getSwapBehavior() const override;
// D3D implementations
SwapChainD3D *getSwapChain() const;
@@ -54,28 +63,36 @@ class SurfaceD3D : public SurfaceImpl
// Returns true if swapchain changed due to resize or interval update
bool checkForOutOfDateSwapChain();
+ gl::Error getAttachmentRenderTarget(const gl::FramebufferAttachment::Target &target,
+ FramebufferAttachmentRenderTarget **rtOut) override;
+
private:
- SurfaceD3D(RendererD3D *renderer, egl::Display *display, const egl::Config *config, EGLint width, EGLint height,
- EGLint fixedSize, EGLClientBuffer shareHandle, EGLNativeWindowType window);
+ SurfaceD3D(RendererD3D *renderer,
+ egl::Display *display,
+ const egl::Config *config,
+ EGLint width,
+ EGLint height,
+ EGLint fixedSize,
+ EGLint orientation,
+ EGLint directComposition,
+ EGLClientBuffer shareHandle,
+ EGLNativeWindowType window);
egl::Error swapRect(EGLint x, EGLint y, EGLint width, EGLint height);
egl::Error resetSwapChain(int backbufferWidth, int backbufferHeight);
egl::Error resizeSwapChain(int backbufferWidth, int backbufferHeight);
- void subclassWindow();
- void unsubclassWindow();
-
RendererD3D *mRenderer;
egl::Display *mDisplay;
bool mFixedSize;
+ GLint mOrientation;
GLenum mRenderTargetFormat;
GLenum mDepthStencilFormat;
SwapChainD3D *mSwapChain;
bool mSwapIntervalDirty;
- bool mWindowSubclassed; // Indicates whether we successfully subclassed mWindow for WM_RESIZE hooking
NativeWindow mNativeWindow; // Handler for the Window that the surface is created for.
EGLint mWidth;
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/SwapChainD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/SwapChainD3D.h
index da36e52ea7..171cab54dd 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/SwapChainD3D.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/SwapChainD3D.h
@@ -31,7 +31,7 @@ class SwapChainD3D : angle::NonCopyable
{
public:
SwapChainD3D(rx::NativeWindow nativeWindow, HANDLE shareHandle, GLenum backBufferFormat, GLenum depthBufferFormat)
- : mNativeWindow(nativeWindow), mShareHandle(shareHandle), mBackBufferFormat(backBufferFormat), mDepthBufferFormat(depthBufferFormat)
+ : mNativeWindow(nativeWindow), mOffscreenRenderTargetFormat(backBufferFormat), mDepthBufferFormat(depthBufferFormat), mShareHandle(shareHandle)
{
}
@@ -46,14 +46,15 @@ class SwapChainD3D : angle::NonCopyable
virtual RenderTargetD3D *getColorRenderTarget() = 0;
virtual RenderTargetD3D *getDepthStencilRenderTarget() = 0;
- GLenum GetBackBufferInternalFormat() const { return mBackBufferFormat; }
+ GLenum GetRenderTargetInternalFormat() const { return mOffscreenRenderTargetFormat; }
GLenum GetDepthBufferInternalFormat() const { return mDepthBufferFormat; }
HANDLE getShareHandle() { return mShareHandle; }
+ virtual void *getKeyedMutex() = 0;
protected:
rx::NativeWindow mNativeWindow; // Handler for the Window that the surface is created for.
- const GLenum mBackBufferFormat;
+ const GLenum mOffscreenRenderTargetFormat;
const GLenum mDepthBufferFormat;
HANDLE mShareHandle;
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureD3D.cpp
index 78b03f2283..430576b318 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureD3D.cpp
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureD3D.cpp
@@ -13,11 +13,13 @@
#include "libANGLE/Buffer.h"
#include "libANGLE/Config.h"
#include "libANGLE/Framebuffer.h"
+#include "libANGLE/Image.h"
#include "libANGLE/Surface.h"
#include "libANGLE/Texture.h"
#include "libANGLE/formatutils.h"
#include "libANGLE/renderer/BufferImpl.h"
#include "libANGLE/renderer/d3d/BufferD3D.h"
+#include "libANGLE/renderer/d3d/EGLImageD3D.h"
#include "libANGLE/renderer/d3d/ImageD3D.h"
#include "libANGLE/renderer/d3d/RendererD3D.h"
#include "libANGLE/renderer/d3d/RenderTargetD3D.h"
@@ -157,16 +159,12 @@ bool TextureD3D::shouldUseSetData(const ImageD3D *image) const
return (mTexStorage && !internalFormat.compressed);
}
-gl::Error TextureD3D::setImage(const gl::ImageIndex &index, GLenum type,
- const gl::PixelUnpackState &unpack, const uint8_t *pixels,
- ptrdiff_t layerOffset)
+gl::Error TextureD3D::setImageImpl(const gl::ImageIndex &index,
+ GLenum type,
+ const gl::PixelUnpackState &unpack,
+ const uint8_t *pixels,
+ ptrdiff_t layerOffset)
{
- if (unpack.skipRows != 0 || unpack.skipPixels != 0 || unpack.imageHeight != 0 || unpack.skipImages != 0)
- {
- UNIMPLEMENTED();
- return gl::Error(GL_INVALID_OPERATION, "unimplemented pixel store state");
- }
-
ImageD3D *image = getImage(index);
ASSERT(image);
@@ -185,7 +183,7 @@ gl::Error TextureD3D::setImage(const gl::ImageIndex &index, GLenum type,
return error;
}
- if (pixelData != NULL)
+ if (pixelData != nullptr)
{
if (shouldUseSetData(image))
{
@@ -247,15 +245,11 @@ gl::Error TextureD3D::subImage(const gl::ImageIndex &index, const gl::Box &area,
return gl::Error(GL_NO_ERROR);
}
-gl::Error TextureD3D::setCompressedImage(const gl::ImageIndex &index, const gl::PixelUnpackState &unpack,
- const uint8_t *pixels, ptrdiff_t layerOffset)
+gl::Error TextureD3D::setCompressedImageImpl(const gl::ImageIndex &index,
+ const gl::PixelUnpackState &unpack,
+ const uint8_t *pixels,
+ ptrdiff_t layerOffset)
{
- if (unpack.skipRows != 0 || unpack.skipPixels != 0 || unpack.imageHeight != 0 || unpack.skipImages != 0)
- {
- UNIMPLEMENTED();
- return gl::Error(GL_INVALID_OPERATION, "unimplemented pixel store state");
- }
-
// We no longer need the "GLenum format" parameter to TexImage to determine what data format "pixels" contains.
// From our image internal format we know how many channels to expect, and "type" gives the format of pixel's components.
const uint8_t *pixelData = NULL;
@@ -287,12 +281,6 @@ gl::Error TextureD3D::subImageCompressed(const gl::ImageIndex &index, const gl::
const gl::PixelUnpackState &unpack, const uint8_t *pixels,
ptrdiff_t layerOffset)
{
- if (unpack.skipRows != 0 || unpack.skipPixels != 0 || unpack.imageHeight != 0 || unpack.skipImages != 0)
- {
- UNIMPLEMENTED();
- return gl::Error(GL_INVALID_OPERATION, "unimplemented pixel store state");
- }
-
const uint8_t *pixelData = NULL;
gl::Error error = GetUnpackPointer(unpack, pixels, layerOffset, &pixelData);
if (error.isError())
@@ -325,6 +313,15 @@ bool TextureD3D::isFastUnpackable(const gl::PixelUnpackState &unpack, GLenum siz
gl::Error TextureD3D::fastUnpackPixels(const gl::PixelUnpackState &unpack, const uint8_t *pixels, const gl::Box &destArea,
GLenum sizedInternalFormat, GLenum type, RenderTargetD3D *destRenderTarget)
{
+ if (unpack.skipRows != 0 || unpack.skipPixels != 0 || unpack.imageHeight != 0 ||
+ unpack.skipImages != 0)
+ {
+ // TODO(jmadill): additional unpack parameters
+ UNIMPLEMENTED();
+ return gl::Error(GL_INVALID_OPERATION,
+ "Unimplemented pixel store parameters in fastUnpackPixels");
+ }
+
// No-op
if (destArea.width <= 0 && destArea.height <= 0 && destArea.depth <= 0)
{
@@ -337,7 +334,7 @@ gl::Error TextureD3D::fastUnpackPixels(const gl::PixelUnpackState &unpack, const
uintptr_t offset = reinterpret_cast<uintptr_t>(pixels);
- gl::Error error = mRenderer->fastCopyBufferToTexture(unpack, offset, destRenderTarget, sizedInternalFormat, type, destArea);
+ gl::Error error = mRenderer->fastCopyBufferToTexture(unpack, static_cast<unsigned int>(offset), destRenderTarget, sizedInternalFormat, type, destArea);
if (error.isError())
{
return error;
@@ -376,7 +373,7 @@ ImageD3D *TextureD3D::getBaseLevelImage() const
return getImage(getImageIndex(0, 0));
}
-gl::Error TextureD3D::generateMipmaps()
+gl::Error TextureD3D::generateMipmaps(const gl::TextureState &textureState)
{
GLint mipCount = mipLevels();
@@ -405,6 +402,38 @@ gl::Error TextureD3D::generateMipmaps()
// Set up proper mipmap chain in our Image array.
initMipmapsImages();
+ if (mTexStorage && mTexStorage->supportsNativeMipmapFunction())
+ {
+ gl::Error error = updateStorage();
+ if (error.isError())
+ {
+ return error;
+ }
+
+ // Generate the mipmap chain using the ad-hoc DirectX function.
+ error = mRenderer->generateMipmapsUsingD3D(mTexStorage, textureState);
+ if (error.isError())
+ {
+ return error;
+ }
+ }
+ else
+ {
+ // Generate the mipmap chain, one level at a time.
+ gl::Error error = generateMipmapsUsingImages();
+ if (error.isError())
+ {
+ return error;
+ }
+ }
+
+ return gl::Error(GL_NO_ERROR);
+}
+
+gl::Error TextureD3D::generateMipmapsUsingImages()
+{
+ GLint mipCount = mipLevels();
+
// We know that all layers have the same dimension, for the texture to be complete
GLint layerCount = static_cast<GLint>(getLayerCount(0));
@@ -421,9 +450,7 @@ gl::Error TextureD3D::generateMipmaps()
gl::ImageIndex srcIndex = getImageIndex(0, layer);
ImageD3D *image = getImage(srcIndex);
- gl::Box area(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth());
- gl::Offset offset(0, 0, 0);
- gl::Error error = image->copy(offset, area, srcIndex, mTexStorage);
+ gl::Error error = image->copyFromTexStorage(srcIndex, mTexStorage);
if (error.isError())
{
return error;
@@ -576,9 +603,19 @@ gl::Error TextureD3D::commitRegion(const gl::ImageIndex &index, const gl::Box &r
return gl::Error(GL_NO_ERROR);
}
+gl::Error TextureD3D::getAttachmentRenderTarget(const gl::FramebufferAttachment::Target &target,
+ FramebufferAttachmentRenderTarget **rtOut)
+{
+ RenderTargetD3D *rtD3D = nullptr;
+ gl::Error error = getRenderTarget(target.textureIndex(), &rtD3D);
+ *rtOut = static_cast<FramebufferAttachmentRenderTarget *>(rtD3D);
+ return error;
+}
+
TextureD3D_2D::TextureD3D_2D(RendererD3D *renderer)
: TextureD3D(renderer)
{
+ mEGLImageTarget = false;
for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
{
mImageArray[i] = renderer->createImage();
@@ -648,16 +685,23 @@ bool TextureD3D_2D::isDepth(GLint level) const
return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
}
-gl::Error TextureD3D_2D::setImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, GLenum format, GLenum type,
- const gl::PixelUnpackState &unpack, const uint8_t *pixels)
+gl::Error TextureD3D_2D::setImage(GLenum target,
+ size_t imageLevel,
+ GLenum internalFormat,
+ const gl::Extents &size,
+ GLenum format,
+ GLenum type,
+ const gl::PixelUnpackState &unpack,
+ const uint8_t *pixels)
{
ASSERT(target == GL_TEXTURE_2D && size.depth == 1);
GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
bool fastUnpacked = false;
+ GLint level = static_cast<GLint>(imageLevel);
- redefineImage(level, sizedInternalFormat, size);
+ redefineImage(level, sizedInternalFormat, size, false);
gl::ImageIndex index = gl::ImageIndex::Make2D(level);
@@ -688,7 +732,7 @@ gl::Error TextureD3D_2D::setImage(GLenum target, size_t level, GLenum internalFo
if (!fastUnpacked)
{
- gl::Error error = TextureD3D::setImage(index, type, unpack, pixels, 0);
+ gl::Error error = setImageImpl(index, type, unpack, pixels, 0);
if (error.isError())
{
return error;
@@ -698,17 +742,17 @@ gl::Error TextureD3D_2D::setImage(GLenum target, size_t level, GLenum internalFo
return gl::Error(GL_NO_ERROR);
}
-gl::Error TextureD3D_2D::setSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, GLenum type,
- const gl::PixelUnpackState &unpack, const uint8_t *pixels)
+gl::Error TextureD3D_2D::setSubImage(GLenum target,
+ size_t imageLevel,
+ const gl::Box &area,
+ GLenum format,
+ GLenum type,
+ const gl::PixelUnpackState &unpack,
+ const uint8_t *pixels)
{
ASSERT(target == GL_TEXTURE_2D && area.depth == 1 && area.z == 0);
- if (unpack.skipRows != 0 || unpack.skipPixels != 0 || unpack.imageHeight != 0 || unpack.skipImages != 0)
- {
- UNIMPLEMENTED();
- return gl::Error(GL_INVALID_OPERATION, "unimplemented pixel store state");
- }
-
+ GLint level = static_cast<GLint>(imageLevel);
gl::ImageIndex index = gl::ImageIndex::Make2D(level);
if (isFastUnpackable(unpack, getInternalFormat(level)) && isLevelComplete(level))
{
@@ -729,24 +773,29 @@ gl::Error TextureD3D_2D::setSubImage(GLenum target, size_t level, const gl::Box
}
}
-
-gl::Error TextureD3D_2D::setCompressedImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size,
- const gl::PixelUnpackState &unpack, const uint8_t *pixels)
+gl::Error TextureD3D_2D::setCompressedImage(GLenum target,
+ size_t imageLevel,
+ GLenum internalFormat,
+ const gl::Extents &size,
+ const gl::PixelUnpackState &unpack,
+ size_t imageSize,
+ const uint8_t *pixels)
{
ASSERT(target == GL_TEXTURE_2D && size.depth == 1);
+ GLint level = static_cast<GLint>(imageLevel);
// compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
- redefineImage(level, internalFormat, size);
+ redefineImage(level, internalFormat, size, false);
- return TextureD3D::setCompressedImage(gl::ImageIndex::Make2D(level), unpack, pixels, 0);
+ return setCompressedImageImpl(gl::ImageIndex::Make2D(level), unpack, pixels, 0);
}
gl::Error TextureD3D_2D::setCompressedSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format,
- const gl::PixelUnpackState &unpack, const uint8_t *pixels)
+ const gl::PixelUnpackState &unpack, size_t imageSize, const uint8_t *pixels)
{
ASSERT(target == GL_TEXTURE_2D && area.depth == 1 && area.z == 0);
- gl::ImageIndex index = gl::ImageIndex::Make2D(level);
+ gl::ImageIndex index = gl::ImageIndex::Make2D(static_cast<GLint>(level));
gl::Error error = TextureD3D::subImageCompressed(index, area, format, unpack, pixels, 0);
if (error.isError())
{
@@ -756,13 +805,18 @@ gl::Error TextureD3D_2D::setCompressedSubImage(GLenum target, size_t level, cons
return commitRegion(index, area);
}
-gl::Error TextureD3D_2D::copyImage(GLenum target, size_t level, const gl::Rectangle &sourceArea, GLenum internalFormat,
+gl::Error TextureD3D_2D::copyImage(GLenum target,
+ size_t imageLevel,
+ const gl::Rectangle &sourceArea,
+ GLenum internalFormat,
const gl::Framebuffer *source)
{
ASSERT(target == GL_TEXTURE_2D);
+ GLint level = static_cast<GLint>(imageLevel);
GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, GL_UNSIGNED_BYTE);
- redefineImage(level, sizedInternalFormat, gl::Extents(sourceArea.width, sourceArea.height, 1));
+ redefineImage(level, sizedInternalFormat, gl::Extents(sourceArea.width, sourceArea.height, 1),
+ false);
gl::ImageIndex index = gl::ImageIndex::Make2D(level);
gl::Offset destOffset(0, 0, 0);
@@ -771,7 +825,7 @@ gl::Error TextureD3D_2D::copyImage(GLenum target, size_t level, const gl::Rectan
// so we should use the non-rendering copy path.
if (!canCreateRenderTargetForImage(index) || mRenderer->getWorkarounds().zeroMaxLodWorkaround)
{
- gl::Error error = mImageArray[level]->copy(destOffset, sourceArea, source);
+ gl::Error error = mImageArray[level]->copyFromFramebuffer(destOffset, sourceArea, source);
if (error.isError())
{
return error;
@@ -802,7 +856,10 @@ gl::Error TextureD3D_2D::copyImage(GLenum target, size_t level, const gl::Rectan
return gl::Error(GL_NO_ERROR);
}
-gl::Error TextureD3D_2D::copySubImage(GLenum target, size_t level, const gl::Offset &destOffset, const gl::Rectangle &sourceArea,
+gl::Error TextureD3D_2D::copySubImage(GLenum target,
+ size_t imageLevel,
+ const gl::Offset &destOffset,
+ const gl::Rectangle &sourceArea,
const gl::Framebuffer *source)
{
ASSERT(target == GL_TEXTURE_2D && destOffset.z == 0);
@@ -810,13 +867,14 @@ gl::Error TextureD3D_2D::copySubImage(GLenum target, size_t level, const gl::Off
// can only make our texture storage to a render target if level 0 is defined (with a width & height) and
// the current level we're copying to is defined (with appropriate format, width & height)
+ GLint level = static_cast<GLint>(imageLevel);
gl::ImageIndex index = gl::ImageIndex::Make2D(level);
// If the zero max LOD workaround is active, then we can't sample from individual layers of the framebuffer in shaders,
// so we should use the non-rendering copy path.
if (!canCreateRenderTargetForImage(index) || mRenderer->getWorkarounds().zeroMaxLodWorkaround)
{
- gl::Error error = mImageArray[level]->copy(destOffset, sourceArea, source);
+ gl::Error error = mImageArray[level]->copyFromFramebuffer(destOffset, sourceArea, source);
if (error.isError())
{
return error;
@@ -862,17 +920,18 @@ gl::Error TextureD3D_2D::setStorage(GLenum target, size_t levels, GLenum interna
gl::Extents levelSize(std::max(1, size.width >> level),
std::max(1, size.height >> level),
1);
- mImageArray[level]->redefine(GL_TEXTURE_2D, internalFormat, levelSize, true);
+ redefineImage(level, internalFormat, levelSize, true);
}
- for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
+ for (size_t level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
{
- mImageArray[level]->redefine(GL_TEXTURE_2D, GL_NONE, gl::Extents(0, 0, 0), true);
+ redefineImage(level, GL_NONE, gl::Extents(0, 0, 1), true);
}
// TODO(geofflang): Verify storage creation had no errors
bool renderTarget = IsRenderTargetUsage(mUsage);
- TextureStorage *storage = mRenderer->createTextureStorage2D(internalFormat, renderTarget, size.width, size.height, levels, false);
+ TextureStorage *storage = mRenderer->createTextureStorage2D(
+ internalFormat, renderTarget, size.width, size.height, static_cast<int>(levels), false);
gl::Error error = setCompleteTexStorage(storage);
if (error.isError())
@@ -898,7 +957,7 @@ void TextureD3D_2D::bindTexImage(egl::Surface *surface)
GLenum internalformat = surface->getConfig()->renderTargetFormat;
gl::Extents size(surface->getWidth(), surface->getHeight(), 1);
- mImageArray[0]->redefine(GL_TEXTURE_2D, internalformat, size, true);
+ redefineImage(0, internalformat, size, true);
if (mTexStorage)
{
@@ -909,6 +968,7 @@ void TextureD3D_2D::bindTexImage(egl::Surface *surface)
ASSERT(surfaceD3D);
mTexStorage = mRenderer->createTextureStorage2D(surfaceD3D->getSwapChain());
+ mEGLImageTarget = false;
mDirtyImages = true;
}
@@ -922,8 +982,32 @@ void TextureD3D_2D::releaseTexImage()
for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
{
- mImageArray[i]->redefine(GL_TEXTURE_2D, GL_NONE, gl::Extents(0, 0, 0), true);
+ redefineImage(i, GL_NONE, gl::Extents(0, 0, 1), true);
+ }
+}
+
+gl::Error TextureD3D_2D::setEGLImageTarget(GLenum target, egl::Image *image)
+{
+ EGLImageD3D *eglImaged3d = GetImplAs<EGLImageD3D>(image);
+
+ // Set the properties of the base mip level from the EGL image
+ GLenum internalformat = image->getInternalFormat();
+ gl::Extents size(static_cast<int>(image->getWidth()), static_cast<int>(image->getHeight()), 1);
+ redefineImage(0, internalformat, size, true);
+
+ // Clear all other images.
+ for (size_t level = 1; level < ArraySize(mImageArray); level++)
+ {
+ redefineImage(level, GL_NONE, gl::Extents(0, 0, 1), true);
}
+
+ SafeDelete(mTexStorage);
+ mImageArray[0]->markClean();
+
+ mTexStorage = mRenderer->createTextureStorageEGLImage(eglImaged3d);
+ mEGLImageTarget = true;
+
+ return gl::Error(GL_NO_ERROR);
}
void TextureD3D_2D::initMipmapsImages()
@@ -936,16 +1020,10 @@ void TextureD3D_2D::initMipmapsImages()
std::max(getBaseLevelHeight() >> level, 1),
1);
- redefineImage(level, getBaseLevelInternalFormat(), levelSize);
+ redefineImage(level, getBaseLevelInternalFormat(), levelSize, false);
}
}
-unsigned int TextureD3D_2D::getRenderTargetSerial(const gl::ImageIndex &index)
-{
- ASSERT(!index.hasLayer());
- return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
-}
-
gl::Error TextureD3D_2D::getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT)
{
ASSERT(!index.hasLayer());
@@ -1152,7 +1230,10 @@ gl::Error TextureD3D_2D::updateStorageLevel(int level)
return gl::Error(GL_NO_ERROR);
}
-void TextureD3D_2D::redefineImage(GLint level, GLenum internalformat, const gl::Extents &size)
+void TextureD3D_2D::redefineImage(size_t level,
+ GLenum internalformat,
+ const gl::Extents &size,
+ bool forceRelease)
{
ASSERT(size.depth == 1);
@@ -1161,18 +1242,26 @@ void TextureD3D_2D::redefineImage(GLint level, GLenum internalformat, const gl::
const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
const GLenum storageFormat = getBaseLevelInternalFormat();
- mImageArray[level]->redefine(GL_TEXTURE_2D, internalformat, size, false);
+ mImageArray[level]->redefine(GL_TEXTURE_2D, internalformat, size, forceRelease);
if (mTexStorage)
{
- const int storageLevels = mTexStorage->getLevelCount();
+ const size_t storageLevels = mTexStorage->getLevelCount();
+
+ // If the storage was from an EGL image, copy it back into local images to preserve it
+ // while orphaning
+ if (level != 0 && mEGLImageTarget)
+ {
+ // TODO(jmadill): Don't discard error.
+ mImageArray[0]->copyFromTexStorage(gl::ImageIndex::Make2D(0), mTexStorage);
+ }
if ((level >= storageLevels && storageLevels != 0) ||
size.width != storageWidth ||
size.height != storageHeight ||
internalformat != storageFormat) // Discard mismatched storage
{
- for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
+ for (size_t i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
{
mImageArray[i]->markDirty();
}
@@ -1181,6 +1270,9 @@ void TextureD3D_2D::redefineImage(GLint level, GLenum internalformat, const gl::
mDirtyImages = true;
}
}
+
+ // Can't be an EGL image target after being redefined
+ mEGLImageTarget = false;
}
gl::ImageIndexIterator TextureD3D_2D::imageIterator() const
@@ -1261,17 +1353,23 @@ bool TextureD3D_Cube::isDepth(GLint level, GLint layer) const
return gl::GetInternalFormatInfo(getInternalFormat(level, layer)).depthBits > 0;
}
+gl::Error TextureD3D_Cube::setEGLImageTarget(GLenum target, egl::Image *image)
+{
+ UNREACHABLE();
+ return gl::Error(GL_INVALID_OPERATION);
+}
+
gl::Error TextureD3D_Cube::setImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, GLenum format, GLenum type,
const gl::PixelUnpackState &unpack, const uint8_t *pixels)
{
ASSERT(size.depth == 1);
GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
- gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
+ gl::ImageIndex index = gl::ImageIndex::MakeCube(target, static_cast<GLint>(level));
- redefineImage(index.layerIndex, level, sizedInternalFormat, size);
+ redefineImage(index.layerIndex, static_cast<GLint>(level), sizedInternalFormat, size);
- return TextureD3D::setImage(index, type, unpack, pixels, 0);
+ return setImageImpl(index, type, unpack, pixels, 0);
}
gl::Error TextureD3D_Cube::setSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, GLenum type,
@@ -1279,30 +1377,30 @@ gl::Error TextureD3D_Cube::setSubImage(GLenum target, size_t level, const gl::Bo
{
ASSERT(area.depth == 1 && area.z == 0);
- gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
+ gl::ImageIndex index = gl::ImageIndex::MakeCube(target, static_cast<GLint>(level));
return TextureD3D::subImage(index, area, format, type, unpack, pixels, 0);
}
gl::Error TextureD3D_Cube::setCompressedImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size,
- const gl::PixelUnpackState &unpack, const uint8_t *pixels)
+ const gl::PixelUnpackState &unpack, size_t imageSize, const uint8_t *pixels)
{
ASSERT(size.depth == 1);
// compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
size_t faceIndex = gl::CubeMapTextureTargetToLayerIndex(target);
- redefineImage(faceIndex, level, internalFormat, size);
+ redefineImage(static_cast<int>(faceIndex), static_cast<GLint>(level), internalFormat, size);
- gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
- return TextureD3D::setCompressedImage(index, unpack, pixels, 0);
+ gl::ImageIndex index = gl::ImageIndex::MakeCube(target, static_cast<GLint>(level));
+ return setCompressedImageImpl(index, unpack, pixels, 0);
}
gl::Error TextureD3D_Cube::setCompressedSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format,
- const gl::PixelUnpackState &unpack, const uint8_t *pixels)
+ const gl::PixelUnpackState &unpack, size_t imageSize, const uint8_t *pixels)
{
ASSERT(area.depth == 1 && area.z == 0);
- gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
+ gl::ImageIndex index = gl::ImageIndex::MakeCube(target, static_cast<GLint>(level));
gl::Error error = TextureD3D::subImageCompressed(index, area, format, unpack, pixels, 0);
if (error.isError())
@@ -1313,14 +1411,19 @@ gl::Error TextureD3D_Cube::setCompressedSubImage(GLenum target, size_t level, co
return commitRegion(index, area);
}
-gl::Error TextureD3D_Cube::copyImage(GLenum target, size_t level, const gl::Rectangle &sourceArea, GLenum internalFormat,
+gl::Error TextureD3D_Cube::copyImage(GLenum target,
+ size_t imageLevel,
+ const gl::Rectangle &sourceArea,
+ GLenum internalFormat,
const gl::Framebuffer *source)
{
- size_t faceIndex = gl::CubeMapTextureTargetToLayerIndex(target);
+ int faceIndex = static_cast<int>(gl::CubeMapTextureTargetToLayerIndex(target));
GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, GL_UNSIGNED_BYTE);
+ GLint level = static_cast<GLint>(imageLevel);
+
gl::Extents size(sourceArea.width, sourceArea.height, 1);
- redefineImage(faceIndex, level, sizedInternalFormat, size);
+ redefineImage(static_cast<int>(faceIndex), level, sizedInternalFormat, size);
gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
gl::Offset destOffset(0, 0, 0);
@@ -1329,7 +1432,8 @@ gl::Error TextureD3D_Cube::copyImage(GLenum target, size_t level, const gl::Rect
// so we should use the non-rendering copy path.
if (!canCreateRenderTargetForImage(index) || mRenderer->getWorkarounds().zeroMaxLodWorkaround)
{
- gl::Error error = mImageArray[faceIndex][level]->copy(destOffset, sourceArea, source);
+ gl::Error error =
+ mImageArray[faceIndex][level]->copyFromFramebuffer(destOffset, sourceArea, source);
if (error.isError())
{
return error;
@@ -1362,18 +1466,23 @@ gl::Error TextureD3D_Cube::copyImage(GLenum target, size_t level, const gl::Rect
return gl::Error(GL_NO_ERROR);
}
-gl::Error TextureD3D_Cube::copySubImage(GLenum target, size_t level, const gl::Offset &destOffset, const gl::Rectangle &sourceArea,
+gl::Error TextureD3D_Cube::copySubImage(GLenum target,
+ size_t imageLevel,
+ const gl::Offset &destOffset,
+ const gl::Rectangle &sourceArea,
const gl::Framebuffer *source)
{
- size_t faceIndex = gl::CubeMapTextureTargetToLayerIndex(target);
+ int faceIndex = static_cast<int>(gl::CubeMapTextureTargetToLayerIndex(target));
+ GLint level = static_cast<GLint>(imageLevel);
gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
// If the zero max LOD workaround is active, then we can't sample from individual layers of the framebuffer in shaders,
// so we should use the non-rendering copy path.
if (!canCreateRenderTargetForImage(index) || mRenderer->getWorkarounds().zeroMaxLodWorkaround)
{
- gl::Error error = mImageArray[faceIndex][level]->copy(destOffset, sourceArea, source);
+ gl::Error error =
+ mImageArray[faceIndex][level]->copyFromFramebuffer(destOffset, sourceArea, source);
if (error.isError())
{
return error;
@@ -1423,7 +1532,7 @@ gl::Error TextureD3D_Cube::setStorage(GLenum target, size_t levels, GLenum inter
}
}
- for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
+ for (size_t level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
{
for (int faceIndex = 0; faceIndex < 6; faceIndex++)
{
@@ -1434,7 +1543,8 @@ gl::Error TextureD3D_Cube::setStorage(GLenum target, size_t levels, GLenum inter
// TODO(geofflang): Verify storage creation had no errors
bool renderTarget = IsRenderTargetUsage(mUsage);
- TextureStorage *storage = mRenderer->createTextureStorageCube(internalFormat, renderTarget, size.width, levels, false);
+ TextureStorage *storage = mRenderer->createTextureStorageCube(
+ internalFormat, renderTarget, size.width, static_cast<int>(levels), false);
gl::Error error = setCompleteTexStorage(storage);
if (error.isError())
@@ -1508,11 +1618,6 @@ void TextureD3D_Cube::initMipmapsImages()
}
}
-unsigned int TextureD3D_Cube::getRenderTargetSerial(const gl::ImageIndex &index)
-{
- return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
-}
-
gl::Error TextureD3D_Cube::getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT)
{
ASSERT(gl::IsCubeMapTextureTarget(index.type));
@@ -1851,12 +1956,25 @@ bool TextureD3D_3D::isDepth(GLint level) const
return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
}
-gl::Error TextureD3D_3D::setImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, GLenum format, GLenum type,
- const gl::PixelUnpackState &unpack, const uint8_t *pixels)
+gl::Error TextureD3D_3D::setEGLImageTarget(GLenum target, egl::Image *image)
+{
+ UNREACHABLE();
+ return gl::Error(GL_INVALID_OPERATION);
+}
+
+gl::Error TextureD3D_3D::setImage(GLenum target,
+ size_t imageLevel,
+ GLenum internalFormat,
+ const gl::Extents &size,
+ GLenum format,
+ GLenum type,
+ const gl::PixelUnpackState &unpack,
+ const uint8_t *pixels)
{
ASSERT(target == GL_TEXTURE_3D);
GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
+ GLint level = static_cast<GLint>(imageLevel);
redefineImage(level, sizedInternalFormat, size);
bool fastUnpacked = false;
@@ -1890,7 +2008,7 @@ gl::Error TextureD3D_3D::setImage(GLenum target, size_t level, GLenum internalFo
if (!fastUnpacked)
{
- gl::Error error = TextureD3D::setImage(index, type, unpack, pixels, 0);
+ gl::Error error = setImageImpl(index, type, unpack, pixels, 0);
if (error.isError())
{
return error;
@@ -1900,11 +2018,17 @@ gl::Error TextureD3D_3D::setImage(GLenum target, size_t level, GLenum internalFo
return gl::Error(GL_NO_ERROR);
}
-gl::Error TextureD3D_3D::setSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, GLenum type,
- const gl::PixelUnpackState &unpack, const uint8_t *pixels)
+gl::Error TextureD3D_3D::setSubImage(GLenum target,
+ size_t imageLevel,
+ const gl::Box &area,
+ GLenum format,
+ GLenum type,
+ const gl::PixelUnpackState &unpack,
+ const uint8_t *pixels)
{
ASSERT(target == GL_TEXTURE_3D);
+ GLint level = static_cast<GLint>(imageLevel);
gl::ImageIndex index = gl::ImageIndex::Make3D(level);
// Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
@@ -1927,24 +2051,30 @@ gl::Error TextureD3D_3D::setSubImage(GLenum target, size_t level, const gl::Box
}
}
-gl::Error TextureD3D_3D::setCompressedImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size,
- const gl::PixelUnpackState &unpack, const uint8_t *pixels)
+gl::Error TextureD3D_3D::setCompressedImage(GLenum target,
+ size_t imageLevel,
+ GLenum internalFormat,
+ const gl::Extents &size,
+ const gl::PixelUnpackState &unpack,
+ size_t imageSize,
+ const uint8_t *pixels)
{
ASSERT(target == GL_TEXTURE_3D);
+ GLint level = static_cast<GLint>(imageLevel);
// compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
redefineImage(level, internalFormat, size);
gl::ImageIndex index = gl::ImageIndex::Make3D(level);
- return TextureD3D::setCompressedImage(index, unpack, pixels, 0);
+ return setCompressedImageImpl(index, unpack, pixels, 0);
}
gl::Error TextureD3D_3D::setCompressedSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format,
- const gl::PixelUnpackState &unpack, const uint8_t *pixels)
+ const gl::PixelUnpackState &unpack, size_t imageSize, const uint8_t *pixels)
{
ASSERT(target == GL_TEXTURE_3D);
- gl::ImageIndex index = gl::ImageIndex::Make3D(level);
+ gl::ImageIndex index = gl::ImageIndex::Make3D(static_cast<GLint>(level));
gl::Error error = TextureD3D::subImageCompressed(index, area, format, unpack, pixels, 0);
if (error.isError())
{
@@ -1961,16 +2091,20 @@ gl::Error TextureD3D_3D::copyImage(GLenum target, size_t level, const gl::Rectan
return gl::Error(GL_INVALID_OPERATION, "Copying 3D textures is unimplemented.");
}
-gl::Error TextureD3D_3D::copySubImage(GLenum target, size_t level, const gl::Offset &destOffset, const gl::Rectangle &sourceArea,
+gl::Error TextureD3D_3D::copySubImage(GLenum target,
+ size_t imageLevel,
+ const gl::Offset &destOffset,
+ const gl::Rectangle &sourceArea,
const gl::Framebuffer *source)
{
ASSERT(target == GL_TEXTURE_3D);
+ GLint level = static_cast<GLint>(imageLevel);
gl::ImageIndex index = gl::ImageIndex::Make3D(level);
if (canCreateRenderTargetForImage(index))
{
- gl::Error error = mImageArray[level]->copy(destOffset, sourceArea, source);
+ gl::Error error = mImageArray[level]->copyFromFramebuffer(destOffset, sourceArea, source);
if (error.isError())
{
return error;
@@ -2019,14 +2153,16 @@ gl::Error TextureD3D_3D::setStorage(GLenum target, size_t levels, GLenum interna
mImageArray[level]->redefine(GL_TEXTURE_3D, internalFormat, levelSize, true);
}
- for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
+ for (size_t level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
{
mImageArray[level]->redefine(GL_TEXTURE_3D, GL_NONE, gl::Extents(0, 0, 0), true);
}
// TODO(geofflang): Verify storage creation had no errors
bool renderTarget = IsRenderTargetUsage(mUsage);
- TextureStorage *storage = mRenderer->createTextureStorage3D(internalFormat, renderTarget, size.width, size.height, size.depth, levels);
+ TextureStorage *storage =
+ mRenderer->createTextureStorage3D(internalFormat, renderTarget, size.width, size.height,
+ size.depth, static_cast<int>(levels));
gl::Error error = setCompleteTexStorage(storage);
if (error.isError())
@@ -2071,11 +2207,6 @@ void TextureD3D_3D::initMipmapsImages()
}
}
-unsigned int TextureD3D_3D::getRenderTargetSerial(const gl::ImageIndex &index)
-{
- return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
-}
-
gl::Error TextureD3D_3D::getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT)
{
// ensure the underlying texture is created
@@ -2384,23 +2515,37 @@ bool TextureD3D_2DArray::isDepth(GLint level) const
return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
}
-gl::Error TextureD3D_2DArray::setImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, GLenum format, GLenum type,
- const gl::PixelUnpackState &unpack, const uint8_t *pixels)
+gl::Error TextureD3D_2DArray::setEGLImageTarget(GLenum target, egl::Image *image)
+{
+ UNREACHABLE();
+ return gl::Error(GL_INVALID_OPERATION);
+}
+
+gl::Error TextureD3D_2DArray::setImage(GLenum target,
+ size_t imageLevel,
+ GLenum internalFormat,
+ const gl::Extents &size,
+ GLenum format,
+ GLenum type,
+ const gl::PixelUnpackState &unpack,
+ const uint8_t *pixels)
{
ASSERT(target == GL_TEXTURE_2D_ARRAY);
GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
+ GLint level = static_cast<GLint>(imageLevel);
redefineImage(level, sizedInternalFormat, size);
const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(sizedInternalFormat);
- GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, size.width, size.height, unpack.alignment, unpack.rowLength);
+ GLsizei inputDepthPitch = formatInfo.computeDepthPitch(
+ type, size.width, size.height, unpack.alignment, unpack.rowLength, unpack.imageHeight);
for (int i = 0; i < size.depth; i++)
{
const ptrdiff_t layerOffset = (inputDepthPitch * i);
gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, i);
- gl::Error error = TextureD3D::setImage(index, type, unpack, pixels, layerOffset);
+ gl::Error error = setImageImpl(index, type, unpack, pixels, layerOffset);
if (error.isError())
{
return error;
@@ -2410,13 +2555,19 @@ gl::Error TextureD3D_2DArray::setImage(GLenum target, size_t level, GLenum inter
return gl::Error(GL_NO_ERROR);
}
-gl::Error TextureD3D_2DArray::setSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, GLenum type,
- const gl::PixelUnpackState &unpack, const uint8_t *pixels)
+gl::Error TextureD3D_2DArray::setSubImage(GLenum target,
+ size_t imageLevel,
+ const gl::Box &area,
+ GLenum format,
+ GLenum type,
+ const gl::PixelUnpackState &unpack,
+ const uint8_t *pixels)
{
ASSERT(target == GL_TEXTURE_2D_ARRAY);
-
+ GLint level = static_cast<GLint>(imageLevel);
const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(getInternalFormat(level));
- GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, area.width, area.height, unpack.alignment, unpack.rowLength);
+ GLsizei inputDepthPitch = formatInfo.computeDepthPitch(
+ type, area.width, area.height, unpack.alignment, unpack.rowLength, unpack.imageHeight);
for (int i = 0; i < area.depth; i++)
{
@@ -2436,23 +2587,30 @@ gl::Error TextureD3D_2DArray::setSubImage(GLenum target, size_t level, const gl:
return gl::Error(GL_NO_ERROR);
}
-gl::Error TextureD3D_2DArray::setCompressedImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size,
- const gl::PixelUnpackState &unpack, const uint8_t *pixels)
+gl::Error TextureD3D_2DArray::setCompressedImage(GLenum target,
+ size_t imageLevel,
+ GLenum internalFormat,
+ const gl::Extents &size,
+ const gl::PixelUnpackState &unpack,
+ size_t imageSize,
+ const uint8_t *pixels)
{
ASSERT(target == GL_TEXTURE_2D_ARRAY);
+ GLint level = static_cast<GLint>(imageLevel);
// compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
redefineImage(level, internalFormat, size);
const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat);
- GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, size.width, size.height, 1, 0);
+ GLsizei inputDepthPitch =
+ formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, size.width, size.height, 1, 0, 0);
for (int i = 0; i < size.depth; i++)
{
const ptrdiff_t layerOffset = (inputDepthPitch * i);
gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, i);
- gl::Error error = TextureD3D::setCompressedImage(index, unpack, pixels, layerOffset);
+ gl::Error error = setCompressedImageImpl(index, unpack, pixels, layerOffset);
if (error.isError())
{
return error;
@@ -2463,12 +2621,13 @@ gl::Error TextureD3D_2DArray::setCompressedImage(GLenum target, size_t level, GL
}
gl::Error TextureD3D_2DArray::setCompressedSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format,
- const gl::PixelUnpackState &unpack, const uint8_t *pixels)
+ const gl::PixelUnpackState &unpack, size_t imageSize, const uint8_t *pixels)
{
ASSERT(target == GL_TEXTURE_2D_ARRAY);
const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
- GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, area.width, area.height, 1, 0);
+ GLsizei inputDepthPitch =
+ formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, area.width, area.height, 1, 0, 0);
for (int i = 0; i < area.depth; i++)
{
@@ -2477,7 +2636,7 @@ gl::Error TextureD3D_2DArray::setCompressedSubImage(GLenum target, size_t level,
gl::Box layerArea(area.x, area.y, 0, area.width, area.height, 1);
- gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
+ gl::ImageIndex index = gl::ImageIndex::Make2DArray(static_cast<GLint>(level), layer);
gl::Error error = TextureD3D::subImageCompressed(index, layerArea, format, unpack, pixels, layerOffset);
if (error.isError())
{
@@ -2501,17 +2660,22 @@ gl::Error TextureD3D_2DArray::copyImage(GLenum target, size_t level, const gl::R
return gl::Error(GL_INVALID_OPERATION, "Copying 2D array textures is unimplemented.");
}
-gl::Error TextureD3D_2DArray::copySubImage(GLenum target, size_t level, const gl::Offset &destOffset, const gl::Rectangle &sourceArea,
+gl::Error TextureD3D_2DArray::copySubImage(GLenum target,
+ size_t imageLevel,
+ const gl::Offset &destOffset,
+ const gl::Rectangle &sourceArea,
const gl::Framebuffer *source)
{
ASSERT(target == GL_TEXTURE_2D_ARRAY);
+ GLint level = static_cast<GLint>(imageLevel);
gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, destOffset.z);
if (canCreateRenderTargetForImage(index))
{
gl::Offset destLayerOffset(destOffset.x, destOffset.y, 0);
- gl::Error error = mImageArray[level][destOffset.z]->copy(destLayerOffset, sourceArea, source);
+ gl::Error error = mImageArray[level][destOffset.z]->copyFromFramebuffer(destLayerOffset,
+ sourceArea, source);
if (error.isError())
{
return error;
@@ -2575,7 +2739,9 @@ gl::Error TextureD3D_2DArray::setStorage(GLenum target, size_t levels, GLenum in
// TODO(geofflang): Verify storage creation had no errors
bool renderTarget = IsRenderTargetUsage(mUsage);
- TextureStorage *storage = mRenderer->createTextureStorage2DArray(internalFormat, renderTarget, size.width, size.height, size.depth, levels);
+ TextureStorage *storage =
+ mRenderer->createTextureStorage2DArray(internalFormat, renderTarget, size.width,
+ size.height, size.depth, static_cast<int>(levels));
gl::Error error = setCompleteTexStorage(storage);
if (error.isError())
@@ -2625,11 +2791,6 @@ void TextureD3D_2DArray::initMipmapsImages()
}
}
-unsigned int TextureD3D_2DArray::getRenderTargetSerial(const gl::ImageIndex &index)
-{
- return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
-}
-
gl::Error TextureD3D_2DArray::getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT)
{
// ensure the underlying texture is created
@@ -2840,21 +3001,30 @@ void TextureD3D_2DArray::redefineImage(GLint level, GLenum internalformat, const
const int storageDepth = getLayerCount(0);
const GLenum storageFormat = getBaseLevelInternalFormat();
- for (int layer = 0; layer < mLayerCounts[level]; layer++)
+ // Only reallocate the layers if the size doesn't match
+ if (size.depth != mLayerCounts[level])
{
- delete mImageArray[level][layer];
+ for (int layer = 0; layer < mLayerCounts[level]; layer++)
+ {
+ SafeDelete(mImageArray[level][layer]);
+ }
+ SafeDeleteArray(mImageArray[level]);
+ mLayerCounts[level] = size.depth;
+
+ if (size.depth > 0)
+ {
+ mImageArray[level] = new ImageD3D*[size.depth];
+ for (int layer = 0; layer < mLayerCounts[level]; layer++)
+ {
+ mImageArray[level][layer] = mRenderer->createImage();
+ }
+ }
}
- delete[] mImageArray[level];
- mImageArray[level] = NULL;
- mLayerCounts[level] = size.depth;
if (size.depth > 0)
{
- mImageArray[level] = new ImageD3D*[size.depth]();
-
for (int layer = 0; layer < mLayerCounts[level]; layer++)
{
- mImageArray[level][layer] = mRenderer->createImage();
mImageArray[level][layer]->redefine(GL_TEXTURE_2D_ARRAY, internalformat,
gl::Extents(size.width, size.height, 1), false);
}
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureD3D.h
index d94be49a08..1d5faee703 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureD3D.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureD3D.h
@@ -20,8 +20,7 @@ class Framebuffer;
namespace rx
{
-
-class ImageD3D;
+class EGLImageD3D;
class ImageD3D;
class RendererD3D;
class RenderTargetD3D;
@@ -50,7 +49,6 @@ class TextureD3D : public TextureImpl
bool isImmutable() const { return mImmutable; }
virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT) = 0;
- virtual unsigned int getRenderTargetSerial(const gl::ImageIndex &index) = 0;
// Returns an iterator over all "Images" for this particular Texture.
virtual gl::ImageIndexIterator imageIterator() const = 0;
@@ -60,18 +58,25 @@ class TextureD3D : public TextureImpl
virtual gl::ImageIndex getImageIndex(GLint mip, GLint layer) const = 0;
virtual bool isValidIndex(const gl::ImageIndex &index) const = 0;
- virtual gl::Error generateMipmaps();
+ gl::Error generateMipmaps(const gl::TextureState &textureState) override;
TextureStorage *getStorage();
ImageD3D *getBaseLevelImage() const;
+ gl::Error getAttachmentRenderTarget(const gl::FramebufferAttachment::Target &target,
+ FramebufferAttachmentRenderTarget **rtOut) override;
+
protected:
- gl::Error setImage(const gl::ImageIndex &index, GLenum type,
- const gl::PixelUnpackState &unpack, const uint8_t *pixels,
- ptrdiff_t layerOffset);
+ gl::Error setImageImpl(const gl::ImageIndex &index,
+ GLenum type,
+ const gl::PixelUnpackState &unpack,
+ const uint8_t *pixels,
+ ptrdiff_t layerOffset);
gl::Error subImage(const gl::ImageIndex &index, const gl::Box &area, GLenum format, GLenum type,
const gl::PixelUnpackState &unpack, const uint8_t *pixels, ptrdiff_t layerOffset);
- gl::Error setCompressedImage(const gl::ImageIndex &index, const gl::PixelUnpackState &unpack,
- const uint8_t *pixels, ptrdiff_t layerOffset);
+ gl::Error setCompressedImageImpl(const gl::ImageIndex &index,
+ const gl::PixelUnpackState &unpack,
+ const uint8_t *pixels,
+ ptrdiff_t layerOffset);
gl::Error subImageCompressed(const gl::ImageIndex &index, const gl::Box &area, GLenum format,
const gl::PixelUnpackState &unpack, const uint8_t *pixels, ptrdiff_t layerOffset);
bool isFastUnpackable(const gl::PixelUnpackState &unpack, GLenum sizedInternalFormat);
@@ -106,6 +111,8 @@ class TextureD3D : public TextureImpl
virtual gl::Error updateStorage() = 0;
bool shouldUseSetData(const ImageD3D *image) const;
+
+ gl::Error generateMipmapsUsingImages();
};
class TextureD3D_2D : public TextureD3D
@@ -129,9 +136,9 @@ class TextureD3D_2D : public TextureD3D
const gl::PixelUnpackState &unpack, const uint8_t *pixels) override;
gl::Error setCompressedImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size,
- const gl::PixelUnpackState &unpack, const uint8_t *pixels) override;
+ const gl::PixelUnpackState &unpack, size_t imageSize, const uint8_t *pixels) override;
gl::Error setCompressedSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format,
- const gl::PixelUnpackState &unpack, const uint8_t *pixels) override;
+ const gl::PixelUnpackState &unpack, size_t imageSize, const uint8_t *pixels) override;
gl::Error copyImage(GLenum target, size_t level, const gl::Rectangle &sourceArea, GLenum internalFormat,
const gl::Framebuffer *source) override;
@@ -143,8 +150,9 @@ class TextureD3D_2D : public TextureD3D
virtual void bindTexImage(egl::Surface *surface);
virtual void releaseTexImage();
+ gl::Error setEGLImageTarget(GLenum target, egl::Image *image) override;
+
virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT);
- virtual unsigned int getRenderTargetSerial(const gl::ImageIndex &index);
virtual gl::ImageIndexIterator imageIterator() const;
virtual gl::ImageIndex getImageIndex(GLint mip, GLint layer) const;
@@ -164,8 +172,12 @@ class TextureD3D_2D : public TextureD3D
gl::Error updateStorageLevel(int level);
- void redefineImage(GLint level, GLenum internalformat, const gl::Extents &size);
+ void redefineImage(size_t level,
+ GLenum internalformat,
+ const gl::Extents &size,
+ bool forceRelease);
+ bool mEGLImageTarget;
ImageD3D *mImageArray[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS];
};
@@ -192,9 +204,9 @@ class TextureD3D_Cube : public TextureD3D
const gl::PixelUnpackState &unpack, const uint8_t *pixels) override;
gl::Error setCompressedImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size,
- const gl::PixelUnpackState &unpack, const uint8_t *pixels) override;
+ const gl::PixelUnpackState &unpack, size_t imageSize, const uint8_t *pixels) override;
gl::Error setCompressedSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format,
- const gl::PixelUnpackState &unpack, const uint8_t *pixels) override;
+ const gl::PixelUnpackState &unpack, size_t imageSize, const uint8_t *pixels) override;
gl::Error copyImage(GLenum target, size_t level, const gl::Rectangle &sourceArea, GLenum internalFormat,
const gl::Framebuffer *source) override;
@@ -206,8 +218,9 @@ class TextureD3D_Cube : public TextureD3D
virtual void bindTexImage(egl::Surface *surface);
virtual void releaseTexImage();
+ gl::Error setEGLImageTarget(GLenum target, egl::Image *image) override;
+
virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT);
- virtual unsigned int getRenderTargetSerial(const gl::ImageIndex &index);
virtual gl::ImageIndexIterator imageIterator() const;
virtual gl::ImageIndex getImageIndex(GLint mip, GLint layer) const;
@@ -254,9 +267,9 @@ class TextureD3D_3D : public TextureD3D
const gl::PixelUnpackState &unpack, const uint8_t *pixels) override;
gl::Error setCompressedImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size,
- const gl::PixelUnpackState &unpack, const uint8_t *pixels) override;
+ const gl::PixelUnpackState &unpack, size_t imageSize, const uint8_t *pixels) override;
gl::Error setCompressedSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format,
- const gl::PixelUnpackState &unpack, const uint8_t *pixels) override;
+ const gl::PixelUnpackState &unpack, size_t imageSize, const uint8_t *pixels) override;
gl::Error copyImage(GLenum target, size_t level, const gl::Rectangle &sourceArea, GLenum internalFormat,
const gl::Framebuffer *source) override;
@@ -268,8 +281,9 @@ class TextureD3D_3D : public TextureD3D
virtual void bindTexImage(egl::Surface *surface);
virtual void releaseTexImage();
+ gl::Error setEGLImageTarget(GLenum target, egl::Image *image) override;
+
virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT);
- virtual unsigned int getRenderTargetSerial(const gl::ImageIndex &index);
virtual gl::ImageIndexIterator imageIterator() const;
virtual gl::ImageIndex getImageIndex(GLint mip, GLint layer) const;
@@ -314,9 +328,9 @@ class TextureD3D_2DArray : public TextureD3D
const gl::PixelUnpackState &unpack, const uint8_t *pixels) override;
gl::Error setCompressedImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size,
- const gl::PixelUnpackState &unpack, const uint8_t *pixels) override;
+ const gl::PixelUnpackState &unpack, size_t imageSize, const uint8_t *pixels) override;
gl::Error setCompressedSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format,
- const gl::PixelUnpackState &unpack, const uint8_t *pixels) override;
+ const gl::PixelUnpackState &unpack, size_t imageSize, const uint8_t *pixels) override;
gl::Error copyImage(GLenum target, size_t level, const gl::Rectangle &sourceArea, GLenum internalFormat,
const gl::Framebuffer *source) override;
@@ -328,8 +342,9 @@ class TextureD3D_2DArray : public TextureD3D
virtual void bindTexImage(egl::Surface *surface);
virtual void releaseTexImage();
+ gl::Error setEGLImageTarget(GLenum target, egl::Image *image) override;
+
virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT);
- virtual unsigned int getRenderTargetSerial(const gl::ImageIndex &index);
virtual gl::ImageIndexIterator imageIterator() const;
virtual gl::ImageIndex getImageIndex(GLint mip, GLint layer) const;
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureStorage.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureStorage.h
index ae2d42ca8a..417237495d 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureStorage.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureStorage.h
@@ -33,12 +33,13 @@ class ImageD3D;
class TextureStorage : angle::NonCopyable
{
public:
- TextureStorage();
- virtual ~TextureStorage() {};
+ TextureStorage() {}
+ virtual ~TextureStorage() {}
virtual int getTopLevel() const = 0;
virtual bool isRenderTarget() const = 0;
virtual bool isManaged() const = 0;
+ virtual bool supportsNativeMipmapFunction() const = 0;
virtual int getLevelCount() const = 0;
virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT) = 0;
@@ -48,18 +49,8 @@ class TextureStorage : angle::NonCopyable
virtual gl::Error setData(const gl::ImageIndex &index, ImageD3D *image, const gl::Box *destBox, GLenum type,
const gl::PixelUnpackState &unpack, const uint8_t *pixelData) = 0;
- unsigned int getRenderTargetSerial(const gl::ImageIndex &index) const;
- unsigned int getTextureSerial() const;
-
// This is a no-op for most implementations of TextureStorage. Some (e.g. TextureStorage11_2D) might override it.
virtual gl::Error useLevelZeroWorkaroundTexture(bool useLevelZeroTexture) { return gl::Error(GL_NO_ERROR); }
-
- protected:
- void initializeSerials(unsigned int rtSerialsToReserve, unsigned int rtSerialsLayerStride);
-
- private:
- unsigned int mFirstRenderTargetSerial;
- unsigned int mRenderTargetSerialsLayerStride;
};
}
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/TransformFeedbackD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/TransformFeedbackD3D.cpp
index 5c0bfdcd5b..80a4ec3ae1 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/TransformFeedbackD3D.cpp
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/TransformFeedbackD3D.cpp
@@ -35,4 +35,12 @@ void TransformFeedbackD3D::resume()
{
}
+void TransformFeedbackD3D::bindGenericBuffer(const BindingPointer<gl::Buffer> &binding)
+{
+}
+
+void TransformFeedbackD3D::bindIndexedBuffer(size_t index, const OffsetBindingPointer<gl::Buffer> &binding)
+{
+}
+
}
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/TransformFeedbackD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/TransformFeedbackD3D.h
index 6b255b4a2b..6925966153 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/TransformFeedbackD3D.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/TransformFeedbackD3D.h
@@ -21,10 +21,13 @@ class TransformFeedbackD3D : public TransformFeedbackImpl
TransformFeedbackD3D();
virtual ~TransformFeedbackD3D();
- virtual void begin(GLenum primitiveMode);
- virtual void end();
- virtual void pause();
- virtual void resume();
+ void begin(GLenum primitiveMode) override;
+ void end() override;
+ void pause() override;
+ void resume() override;
+
+ void bindGenericBuffer(const BindingPointer<gl::Buffer> &binding) override;
+ void bindIndexedBuffer(size_t index, const OffsetBindingPointer<gl::Buffer> &binding) override;
};
}
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/VaryingPacking.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/VaryingPacking.cpp
new file mode 100644
index 0000000000..f2654d34e3
--- /dev/null
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/VaryingPacking.cpp
@@ -0,0 +1,397 @@
+//
+// 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.
+//
+// VaryingPacking:
+// Class which describes a mapping from varyings to registers in D3D
+// for linking between shader stages.
+//
+
+#include "libANGLE/renderer/d3d/VaryingPacking.h"
+
+#include "common/utilities.h"
+#include "compiler/translator/blocklayoutHLSL.h"
+#include "libANGLE/renderer/d3d/DynamicHLSL.h"
+#include "libANGLE/renderer/d3d/ProgramD3D.h"
+
+namespace rx
+{
+
+// Implementation of VaryingPacking::BuiltinVarying
+VaryingPacking::BuiltinVarying::BuiltinVarying() : enabled(false), index(0), systemValue(false)
+{
+}
+
+std::string VaryingPacking::BuiltinVarying::str() const
+{
+ return (systemValue ? semantic : (semantic + Str(index)));
+}
+
+void VaryingPacking::BuiltinVarying::enableSystem(const std::string &systemValueSemantic)
+{
+ enabled = true;
+ semantic = systemValueSemantic;
+ systemValue = true;
+}
+
+void VaryingPacking::BuiltinVarying::enable(const std::string &semanticVal, unsigned int indexVal)
+{
+ enabled = true;
+ semantic = semanticVal;
+ index = indexVal;
+}
+
+// Implementation of VaryingPacking
+VaryingPacking::VaryingPacking(GLuint maxVaryingVectors)
+ : mRegisterMap(maxVaryingVectors), mBuiltinInfo(SHADER_TYPE_MAX)
+{
+}
+
+// Packs varyings into generic varying registers, using the algorithm from
+// See [OpenGL ES Shading Language 1.00 rev. 17] appendix A section 7 page 111
+// Also [OpenGL ES Shading Language 3.00 rev. 4] Section 11 page 119
+// Returns false if unsuccessful.
+bool VaryingPacking::packVarying(const PackedVarying &packedVarying)
+{
+ unsigned int varyingRows = 0;
+ unsigned int varyingColumns = 0;
+
+ const auto &varying = *packedVarying.varying;
+
+ // "Non - square matrices of type matCxR consume the same space as a square matrix of type matN
+ // where N is the greater of C and R.Variables of type mat2 occupies 2 complete rows."
+ // Here we are a bit more conservative and allow packing non-square matrices more tightly.
+ // Make sure we use transposed matrix types to count registers correctly.
+ ASSERT(!varying.isStruct());
+ GLenum transposedType = gl::TransposeMatrixType(varying.type);
+ varyingRows = gl::VariableRowCount(transposedType);
+ varyingColumns = gl::VariableColumnCount(transposedType);
+
+ // "Arrays of size N are assumed to take N times the size of the base type"
+ varyingRows *= varying.elementCount();
+
+ unsigned int maxVaryingVectors = static_cast<unsigned int>(mRegisterMap.size());
+
+ // "For 2, 3 and 4 component variables packing is started using the 1st column of the 1st row.
+ // Variables are then allocated to successive rows, aligning them to the 1st column."
+ if (varyingColumns >= 2 && varyingColumns <= 4)
+ {
+ for (unsigned int row = 0; row <= maxVaryingVectors - varyingRows; ++row)
+ {
+ if (isFree(row, 0, varyingRows, varyingColumns))
+ {
+ insert(row, 0, packedVarying);
+ return true;
+ }
+ }
+
+ // "For 2 component variables, when there are no spare rows, the strategy is switched to
+ // using the highest numbered row and the lowest numbered column where the variable will
+ // fit."
+ if (varyingColumns == 2)
+ {
+ for (unsigned int r = maxVaryingVectors - varyingRows + 1; r-- >= 1;)
+ {
+ if (isFree(r, 2, varyingRows, 2))
+ {
+ insert(r, 2, packedVarying);
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ // "1 component variables have their own packing rule. They are packed in order of size, largest
+ // first. Each variable is placed in the column that leaves the least amount of space in the
+ // column and aligned to the lowest available rows within that column."
+ ASSERT(varyingColumns == 1);
+ unsigned int contiguousSpace[4] = {0};
+ unsigned int bestContiguousSpace[4] = {0};
+ unsigned int totalSpace[4] = {0};
+
+ for (unsigned int row = 0; row < maxVaryingVectors; ++row)
+ {
+ for (unsigned int column = 0; column < 4; ++column)
+ {
+ if (mRegisterMap[row][column])
+ {
+ contiguousSpace[column] = 0;
+ }
+ else
+ {
+ contiguousSpace[column]++;
+ totalSpace[column]++;
+
+ if (contiguousSpace[column] > bestContiguousSpace[column])
+ {
+ bestContiguousSpace[column] = contiguousSpace[column];
+ }
+ }
+ }
+ }
+
+ unsigned int bestColumn = 0;
+ for (unsigned int column = 1; column < 4; ++column)
+ {
+ if (bestContiguousSpace[column] >= varyingRows &&
+ (bestContiguousSpace[bestColumn] < varyingRows ||
+ totalSpace[column] < totalSpace[bestColumn]))
+ {
+ bestColumn = column;
+ }
+ }
+
+ if (bestContiguousSpace[bestColumn] >= varyingRows)
+ {
+ for (unsigned int row = 0; row < maxVaryingVectors; row++)
+ {
+ if (isFree(row, bestColumn, varyingRows, 1))
+ {
+ for (unsigned int arrayIndex = 0; arrayIndex < varyingRows; ++arrayIndex)
+ {
+ // If varyingRows > 1, it must be an array.
+ PackedVaryingRegister registerInfo;
+ registerInfo.packedVarying = &packedVarying;
+ registerInfo.registerRow = row + arrayIndex;
+ registerInfo.registerColumn = bestColumn;
+ registerInfo.varyingArrayIndex = arrayIndex;
+ registerInfo.varyingRowIndex = 0;
+ mRegisterList.push_back(registerInfo);
+ mRegisterMap[row + arrayIndex][bestColumn] = true;
+ }
+ break;
+ }
+ }
+ return true;
+ }
+
+ return false;
+}
+
+bool VaryingPacking::isFree(unsigned int registerRow,
+ unsigned int registerColumn,
+ unsigned int varyingRows,
+ unsigned int varyingColumns) const
+{
+ for (unsigned int row = 0; row < varyingRows; ++row)
+ {
+ ASSERT(registerRow + row < mRegisterMap.size());
+ for (unsigned int column = 0; column < varyingColumns; ++column)
+ {
+ ASSERT(registerColumn + column < 4);
+ if (mRegisterMap[registerRow + row][registerColumn + column])
+ {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+void VaryingPacking::insert(unsigned int registerRow,
+ unsigned int registerColumn,
+ const PackedVarying &packedVarying)
+{
+ unsigned int varyingRows = 0;
+ unsigned int varyingColumns = 0;
+
+ const auto &varying = *packedVarying.varying;
+ ASSERT(!varying.isStruct());
+ GLenum transposedType = gl::TransposeMatrixType(varying.type);
+ varyingRows = gl::VariableRowCount(transposedType);
+ varyingColumns = gl::VariableColumnCount(transposedType);
+
+ PackedVaryingRegister registerInfo;
+ registerInfo.packedVarying = &packedVarying;
+ registerInfo.registerColumn = registerColumn;
+
+ for (unsigned int arrayElement = 0; arrayElement < varying.elementCount(); ++arrayElement)
+ {
+ for (unsigned int varyingRow = 0; varyingRow < varyingRows; ++varyingRow)
+ {
+ registerInfo.registerRow = registerRow + (arrayElement * varyingRows) + varyingRow;
+ registerInfo.varyingRowIndex = varyingRow;
+ registerInfo.varyingArrayIndex = arrayElement;
+ mRegisterList.push_back(registerInfo);
+
+ for (unsigned int columnIndex = 0; columnIndex < varyingColumns; ++columnIndex)
+ {
+ mRegisterMap[registerInfo.registerRow][registerColumn + columnIndex] = true;
+ }
+ }
+ }
+}
+
+// See comment on packVarying.
+bool VaryingPacking::packVaryings(gl::InfoLog &infoLog,
+ const std::vector<PackedVarying> &packedVaryings,
+ const std::vector<std::string> &transformFeedbackVaryings)
+{
+ std::set<std::string> uniqueVaryingNames;
+
+ // "Variables are packed into the registers one at a time so that they each occupy a contiguous
+ // subrectangle. No splitting of variables is permitted."
+ for (const PackedVarying &packedVarying : packedVaryings)
+ {
+ const auto &varying = *packedVarying.varying;
+
+ // Do not assign registers to built-in or unreferenced varyings
+ if (varying.isBuiltIn() || (!varying.staticUse && !packedVarying.isStructField()))
+ {
+ continue;
+ }
+
+ ASSERT(!varying.isStruct());
+ ASSERT(uniqueVaryingNames.count(varying.name) == 0);
+
+ if (packVarying(packedVarying))
+ {
+ uniqueVaryingNames.insert(varying.name);
+ }
+ else
+ {
+ infoLog << "Could not pack varying " << varying.name;
+ return false;
+ }
+ }
+
+ for (const std::string &transformFeedbackVaryingName : transformFeedbackVaryings)
+ {
+ if (transformFeedbackVaryingName.compare(0, 3, "gl_") == 0)
+ {
+ // do not pack builtin XFB varyings
+ continue;
+ }
+
+ for (const PackedVarying &packedVarying : packedVaryings)
+ {
+ const auto &varying = *packedVarying.varying;
+
+ // Make sure transform feedback varyings aren't optimized out.
+ if (uniqueVaryingNames.count(transformFeedbackVaryingName) == 0)
+ {
+ bool found = false;
+ if (transformFeedbackVaryingName == varying.name)
+ {
+ if (!packVarying(packedVarying))
+ {
+ infoLog << "Could not pack varying " << varying.name;
+ return false;
+ }
+
+ found = true;
+ break;
+ }
+ if (!found)
+ {
+ infoLog << "Transform feedback varying " << transformFeedbackVaryingName
+ << " does not exist in the vertex shader.";
+ return false;
+ }
+ }
+ }
+ }
+
+ // Sort the packed register list
+ std::sort(mRegisterList.begin(), mRegisterList.end());
+
+ // Assign semantic indices
+ for (unsigned int semanticIndex = 0;
+ semanticIndex < static_cast<unsigned int>(mRegisterList.size()); ++semanticIndex)
+ {
+ mRegisterList[semanticIndex].semanticIndex = semanticIndex;
+ }
+
+ return true;
+}
+
+unsigned int VaryingPacking::getRegisterCount() const
+{
+ unsigned int count = 0;
+
+ for (const Register &reg : mRegisterMap)
+ {
+ if (reg.data[0] || reg.data[1] || reg.data[2] || reg.data[3])
+ {
+ ++count;
+ }
+ }
+
+ if (mBuiltinInfo[SHADER_PIXEL].glFragCoord.enabled)
+ {
+ ++count;
+ }
+
+ if (mBuiltinInfo[SHADER_PIXEL].glPointCoord.enabled)
+ {
+ ++count;
+ }
+
+ return count;
+}
+
+void VaryingPacking::enableBuiltins(ShaderType shaderType,
+ const ProgramD3DMetadata &programMetadata)
+{
+ int majorShaderModel = programMetadata.getRendererMajorShaderModel();
+ bool position = programMetadata.usesTransformFeedbackGLPosition();
+ bool fragCoord = programMetadata.usesFragCoord();
+ bool pointCoord = shaderType == SHADER_VERTEX ? programMetadata.addsPointCoordToVertexShader()
+ : programMetadata.usesPointCoord();
+ bool pointSize = programMetadata.usesSystemValuePointSize();
+ bool hlsl4 = (majorShaderModel >= 4);
+ const std::string &userSemantic = GetVaryingSemantic(majorShaderModel, pointSize);
+
+ unsigned int reservedSemanticIndex = getMaxSemanticIndex();
+
+ BuiltinInfo *builtins = &mBuiltinInfo[shaderType];
+
+ if (hlsl4)
+ {
+ builtins->dxPosition.enableSystem("SV_Position");
+ }
+ else if (shaderType == SHADER_PIXEL)
+ {
+ builtins->dxPosition.enableSystem("VPOS");
+ }
+ else
+ {
+ builtins->dxPosition.enableSystem("POSITION");
+ }
+
+ if (position)
+ {
+ builtins->glPosition.enable(userSemantic, reservedSemanticIndex++);
+ }
+
+ if (fragCoord)
+ {
+ builtins->glFragCoord.enable(userSemantic, reservedSemanticIndex++);
+ }
+
+ if (pointCoord)
+ {
+ // SM3 reserves the TEXCOORD semantic for point sprite texcoords (gl_PointCoord)
+ // In D3D11 we manually compute gl_PointCoord in the GS.
+ if (hlsl4)
+ {
+ builtins->glPointCoord.enable(userSemantic, reservedSemanticIndex++);
+ }
+ else
+ {
+ builtins->glPointCoord.enable("TEXCOORD", 0);
+ }
+ }
+
+ // Special case: do not include PSIZE semantic in HLSL 3 pixel shaders
+ if (pointSize && (shaderType != SHADER_PIXEL || hlsl4))
+ {
+ builtins->glPointSize.enableSystem("PSIZE");
+ }
+}
+
+} // namespace rx
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/VaryingPacking.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/VaryingPacking.h
new file mode 100644
index 0000000000..ca4640b000
--- /dev/null
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/VaryingPacking.h
@@ -0,0 +1,175 @@
+//
+// 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.
+//
+// VaryingPacking:
+// Class which describes a mapping from varyings to registers in D3D
+// for linking between shader stages.
+//
+
+#ifndef LIBANGLE_RENDERER_D3D_VARYINGPACKING_H_
+#define LIBANGLE_RENDERER_D3D_VARYINGPACKING_H_
+
+#include "libANGLE/renderer/d3d/RendererD3D.h"
+
+namespace rx
+{
+class ProgramD3DMetadata;
+
+struct PackedVarying
+{
+ PackedVarying(const sh::ShaderVariable &varyingIn, sh::InterpolationType interpolationIn)
+ : varying(&varyingIn), vertexOnly(false), interpolation(interpolationIn)
+ {
+ }
+ PackedVarying(const sh::ShaderVariable &varyingIn,
+ sh::InterpolationType interpolationIn,
+ const std::string &parentStructNameIn)
+ : varying(&varyingIn),
+ vertexOnly(false),
+ interpolation(interpolationIn),
+ parentStructName(parentStructNameIn)
+ {
+ }
+
+ bool isStructField() const { return !parentStructName.empty(); }
+
+ const sh::ShaderVariable *varying;
+
+ // Transform feedback varyings can be only referenced in the VS.
+ bool vertexOnly;
+
+ // Cached so we can store sh::ShaderVariable to point to varying fields.
+ sh::InterpolationType interpolation;
+
+ // Struct name
+ std::string parentStructName;
+};
+
+struct PackedVaryingRegister final
+{
+ PackedVaryingRegister()
+ : packedVarying(nullptr),
+ varyingArrayIndex(0),
+ varyingRowIndex(0),
+ registerRow(0),
+ registerColumn(0)
+ {
+ }
+
+ PackedVaryingRegister(const PackedVaryingRegister &) = default;
+ PackedVaryingRegister &operator=(const PackedVaryingRegister &) = default;
+
+ bool operator<(const PackedVaryingRegister &other) const
+ {
+ return sortOrder() < other.sortOrder();
+ }
+
+ unsigned int sortOrder() const
+ {
+ // TODO(jmadill): Handle interpolation types
+ return registerRow * 4 + registerColumn;
+ }
+
+ bool isStructField() const { return !structFieldName.empty(); }
+
+ // Index to the array of varyings.
+ const PackedVarying *packedVarying;
+
+ // The array element of the packed varying.
+ unsigned int varyingArrayIndex;
+
+ // The row of the array element of the packed varying.
+ unsigned int varyingRowIndex;
+
+ // The register row to which we've assigned this packed varying.
+ unsigned int registerRow;
+
+ // The column of the register row into which we've packed this varying.
+ unsigned int registerColumn;
+
+ // Assigned after packing
+ unsigned int semanticIndex;
+
+ // Struct member this varying corresponds to.
+ std::string structFieldName;
+};
+
+class VaryingPacking final : angle::NonCopyable
+{
+ public:
+ VaryingPacking(GLuint maxVaryingVectors);
+
+ bool packVaryings(gl::InfoLog &infoLog,
+ const std::vector<PackedVarying> &packedVaryings,
+ const std::vector<std::string> &transformFeedbackVaryings);
+
+ struct Register
+ {
+ Register() { data[0] = data[1] = data[2] = data[3] = false; }
+
+ bool &operator[](unsigned int index) { return data[index]; }
+ bool operator[](unsigned int index) const { return data[index]; }
+
+ bool data[4];
+ };
+
+ Register &operator[](unsigned int index) { return mRegisterMap[index]; }
+ const Register &operator[](unsigned int index) const { return mRegisterMap[index]; }
+
+ const std::vector<PackedVaryingRegister> &getRegisterList() const { return mRegisterList; }
+ unsigned int getMaxSemanticIndex() const
+ {
+ return static_cast<unsigned int>(mRegisterList.size());
+ }
+ unsigned int getRegisterCount() const;
+
+ void enableBuiltins(ShaderType shaderType, const ProgramD3DMetadata &programMetadata);
+
+ struct BuiltinVarying final : angle::NonCopyable
+ {
+ BuiltinVarying();
+
+ std::string str() const;
+ void enableSystem(const std::string &systemValueSemantic);
+ void enable(const std::string &semanticVal, unsigned int indexVal);
+
+ bool enabled;
+ std::string semantic;
+ unsigned int index;
+ bool systemValue;
+ };
+
+ struct BuiltinInfo
+ {
+ BuiltinVarying dxPosition;
+ BuiltinVarying glPosition;
+ BuiltinVarying glFragCoord;
+ BuiltinVarying glPointCoord;
+ BuiltinVarying glPointSize;
+ };
+
+ const BuiltinInfo &builtins(ShaderType shaderType) const { return mBuiltinInfo[shaderType]; }
+
+ bool usesPointSize() const { return mBuiltinInfo[SHADER_VERTEX].glPointSize.enabled; }
+
+ private:
+ bool packVarying(const PackedVarying &packedVarying);
+ bool isFree(unsigned int registerRow,
+ unsigned int registerColumn,
+ unsigned int varyingRows,
+ unsigned int varyingColumns) const;
+ void insert(unsigned int registerRow,
+ unsigned int registerColumn,
+ const PackedVarying &packedVarying);
+
+ std::vector<Register> mRegisterMap;
+ std::vector<PackedVaryingRegister> mRegisterList;
+
+ std::vector<BuiltinInfo> mBuiltinInfo;
+};
+
+} // namespace rx
+
+#endif // LIBANGLE_RENDERER_D3D_VARYINGPACKING_H_
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexBuffer.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexBuffer.cpp
index 19bd548fce..9efee9db7c 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexBuffer.cpp
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexBuffer.cpp
@@ -90,8 +90,13 @@ gl::Error VertexBufferInterface::discard()
return mVertexBuffer->discard();
}
-gl::Error VertexBufferInterface::storeVertexAttributes(const gl::VertexAttribute &attrib, const gl::VertexAttribCurrentValueData &currentValue,
- GLint start, GLsizei count, GLsizei instances, unsigned int *outStreamOffset)
+gl::Error VertexBufferInterface::storeVertexAttributes(const gl::VertexAttribute &attrib,
+ GLenum currentValueType,
+ GLint start,
+ GLsizei count,
+ GLsizei instances,
+ unsigned int *outStreamOffset,
+ const uint8_t *sourceData)
{
gl::Error error(GL_NO_ERROR);
@@ -102,7 +107,12 @@ gl::Error VertexBufferInterface::storeVertexAttributes(const gl::VertexAttribute
return error;
}
- if (mWritePosition + spaceRequired < mWritePosition)
+ // Align to 16-byte boundary
+ unsigned int alignedSpaceRequired = roundUp(spaceRequired, 16u);
+
+ // Protect against integer overflow
+ if (!IsUnsignedAdditionSafe(mWritePosition, alignedSpaceRequired) ||
+ alignedSpaceRequired < spaceRequired)
{
return gl::Error(GL_OUT_OF_MEMORY, "Internal error, new vertex buffer write position would overflow.");
}
@@ -114,7 +124,7 @@ gl::Error VertexBufferInterface::storeVertexAttributes(const gl::VertexAttribute
}
mReservedSpace = 0;
- error = mVertexBuffer->storeVertexAttributes(attrib, currentValue, start, count, instances, mWritePosition);
+ error = mVertexBuffer->storeVertexAttributes(attrib, currentValueType, start, count, instances, mWritePosition, sourceData);
if (error.isError())
{
return error;
@@ -125,10 +135,7 @@ gl::Error VertexBufferInterface::storeVertexAttributes(const gl::VertexAttribute
*outStreamOffset = mWritePosition;
}
- mWritePosition += spaceRequired;
-
- // Align to 16-byte boundary
- mWritePosition = roundUp(mWritePosition, 16u);
+ mWritePosition += alignedSpaceRequired;
return gl::Error(GL_NO_ERROR);
}
@@ -144,17 +151,18 @@ gl::Error VertexBufferInterface::reserveVertexSpace(const gl::VertexAttribute &a
return error;
}
+ // Align to 16-byte boundary
+ unsigned int alignedRequiredSpace = roundUp(requiredSpace, 16u);
+
// Protect against integer overflow
- if (mReservedSpace + requiredSpace < mReservedSpace)
+ if (!IsUnsignedAdditionSafe(mReservedSpace, alignedRequiredSpace) ||
+ alignedRequiredSpace < requiredSpace)
{
return gl::Error(GL_OUT_OF_MEMORY, "Unable to reserve %u extra bytes in internal vertex buffer, "
"it would result in an overflow.", requiredSpace);
}
- mReservedSpace += requiredSpace;
-
- // Align to 16-byte boundary
- mReservedSpace = roundUp(mReservedSpace, 16u);
+ mReservedSpace += alignedRequiredSpace;
return gl::Error(GL_NO_ERROR);
}
@@ -165,7 +173,7 @@ VertexBuffer* VertexBufferInterface::getVertexBuffer() const
}
bool VertexBufferInterface::directStoragePossible(const gl::VertexAttribute &attrib,
- const gl::VertexAttribCurrentValueData &currentValue) const
+ GLenum currentValueType) const
{
gl::Buffer *buffer = attrib.buffer.get();
BufferD3D *storage = buffer ? GetImplAs<BufferD3D>(buffer) : NULL;
@@ -183,14 +191,14 @@ bool VertexBufferInterface::directStoragePossible(const gl::VertexAttribute &att
if (attrib.type != GL_FLOAT)
{
- gl::VertexFormat vertexFormat(attrib, currentValue.Type);
+ gl::VertexFormatType vertexFormatType = gl::GetVertexFormatType(attrib, currentValueType);
unsigned int outputElementSize;
getVertexBuffer()->getSpaceRequired(attrib, 1, 0, &outputElementSize);
alignment = std::min<size_t>(outputElementSize, 4);
// TODO(jmadill): add VertexFormatCaps
- requiresConversion = (mFactory->getVertexConversionType(vertexFormat) & VERTEX_CONVERT_CPU) != 0;
+ requiresConversion = (mFactory->getVertexConversionType(vertexFormatType) & VERTEX_CONVERT_CPU) != 0;
}
bool isAligned = (static_cast<size_t>(ComputeVertexAttributeStride(attrib)) % alignment == 0) &&
@@ -202,7 +210,7 @@ bool VertexBufferInterface::directStoragePossible(const gl::VertexAttribute &att
StreamingVertexBufferInterface::StreamingVertexBufferInterface(BufferFactoryD3D *factory, std::size_t initialSize)
: VertexBufferInterface(factory, true)
{
- setBufferSize(initialSize);
+ setBufferSize(static_cast<unsigned int>(initialSize));
}
StreamingVertexBufferInterface::~StreamingVertexBufferInterface()
@@ -235,7 +243,7 @@ gl::Error StreamingVertexBufferInterface::reserveSpace(unsigned int size)
}
StaticVertexBufferInterface::StaticVertexBufferInterface(BufferFactoryD3D *factory)
- : VertexBufferInterface(factory, false)
+ : VertexBufferInterface(factory, false), mIsCommitted(false)
{
}
@@ -247,13 +255,14 @@ bool StaticVertexBufferInterface::lookupAttribute(const gl::VertexAttribute &att
{
for (unsigned int element = 0; element < mCache.size(); element++)
{
- if (mCache[element].type == attrib.type &&
- mCache[element].size == attrib.size &&
- mCache[element].stride == ComputeVertexAttributeStride(attrib) &&
+ size_t attribStride = ComputeVertexAttributeStride(attrib);
+
+ if (mCache[element].type == attrib.type && mCache[element].size == attrib.size &&
+ mCache[element].stride == attribStride &&
mCache[element].normalized == attrib.normalized &&
mCache[element].pureInteger == attrib.pureInteger)
{
- size_t offset = (static_cast<size_t>(attrib.offset) % ComputeVertexAttributeStride(attrib));
+ size_t offset = (static_cast<size_t>(attrib.offset) % attribStride);
if (mCache[element].attributeOffset == offset)
{
if (outStreamOffset)
@@ -286,11 +295,16 @@ gl::Error StaticVertexBufferInterface::reserveSpace(unsigned int size)
}
}
-gl::Error StaticVertexBufferInterface::storeVertexAttributes(const gl::VertexAttribute &attrib, const gl::VertexAttribCurrentValueData &currentValue,
- GLint start, GLsizei count, GLsizei instances, unsigned int *outStreamOffset)
+gl::Error StaticVertexBufferInterface::storeVertexAttributes(const gl::VertexAttribute &attrib,
+ GLenum currentValueType,
+ GLint start,
+ GLsizei count,
+ GLsizei instances,
+ unsigned int *outStreamOffset,
+ const uint8_t *sourceData)
{
unsigned int streamOffset;
- gl::Error error = VertexBufferInterface::storeVertexAttributes(attrib, currentValue, start, count, instances, &streamOffset);
+ gl::Error error = VertexBufferInterface::storeVertexAttributes(attrib, currentValueType, start, count, instances, &streamOffset, sourceData);
if (error.isError())
{
return error;
@@ -308,4 +322,11 @@ gl::Error StaticVertexBufferInterface::storeVertexAttributes(const gl::VertexAtt
return gl::Error(GL_NO_ERROR);
}
+void StaticVertexBufferInterface::commit()
+{
+ if (getBufferSize() > 0)
+ {
+ mIsCommitted = true;
+ }
+}
}
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexBuffer.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexBuffer.h
index 5cb03fe3a1..692b6ac506 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexBuffer.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexBuffer.h
@@ -16,6 +16,7 @@
#include <GLES2/gl2.h>
#include <cstddef>
+#include <cstdint>
#include <vector>
namespace gl
@@ -36,8 +37,13 @@ class VertexBuffer : angle::NonCopyable
virtual gl::Error initialize(unsigned int size, bool dynamicUsage) = 0;
- virtual gl::Error storeVertexAttributes(const gl::VertexAttribute &attrib, const gl::VertexAttribCurrentValueData &currentValue,
- GLint start, GLsizei count, GLsizei instances, unsigned int offset) = 0;
+ virtual gl::Error storeVertexAttributes(const gl::VertexAttribute &attrib,
+ GLenum currentValueType,
+ GLint start,
+ GLsizei count,
+ GLsizei instances,
+ unsigned int offset,
+ const uint8_t *sourceData) = 0;
virtual gl::Error getSpaceRequired(const gl::VertexAttribute &attrib, GLsizei count, GLsizei instances,
unsigned int *outSpaceRequired) const = 0;
@@ -70,11 +76,16 @@ class VertexBufferInterface : angle::NonCopyable
unsigned int getSerial() const;
- virtual gl::Error storeVertexAttributes(const gl::VertexAttribute &attrib, const gl::VertexAttribCurrentValueData &currentValue,
- GLint start, GLsizei count, GLsizei instances, unsigned int *outStreamOffset);
+ virtual gl::Error storeVertexAttributes(const gl::VertexAttribute &attrib,
+ GLenum currentValueType,
+ GLint start,
+ GLsizei count,
+ GLsizei instances,
+ unsigned int *outStreamOffset,
+ const uint8_t *sourceData);
bool directStoragePossible(const gl::VertexAttribute &attrib,
- const gl::VertexAttribCurrentValueData &currentValue) const;
+ GLenum currentValueType) const;
VertexBuffer* getVertexBuffer() const;
@@ -114,11 +125,21 @@ class StaticVertexBufferInterface : public VertexBufferInterface
explicit StaticVertexBufferInterface(BufferFactoryD3D *factory);
~StaticVertexBufferInterface();
- gl::Error storeVertexAttributes(const gl::VertexAttribute &attrib, const gl::VertexAttribCurrentValueData &currentValue,
- GLint start, GLsizei count, GLsizei instances, unsigned int *outStreamOffset);
+ gl::Error storeVertexAttributes(const gl::VertexAttribute &attrib,
+ GLenum currentValueType,
+ GLint start,
+ GLsizei count,
+ GLsizei instances,
+ unsigned int *outStreamOffset,
+ const uint8_t *sourceData) override;
bool lookupAttribute(const gl::VertexAttribute &attribute, unsigned int* outStreamFffset);
+ // If a static vertex buffer is committed then no more attribute data can be added to it
+ // A new static vertex buffer should be created instead
+ void commit();
+ bool isCommitted() { return mIsCommitted; }
+
protected:
gl::Error reserveSpace(unsigned int size);
@@ -135,6 +156,7 @@ class StaticVertexBufferInterface : public VertexBufferInterface
unsigned int streamOffset;
};
+ bool mIsCommitted;
std::vector<VertexElement> mCache;
};
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexDataManager.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexDataManager.cpp
index cb70b9e4ef..b392d0f4da 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexDataManager.cpp
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexDataManager.cpp
@@ -35,215 +35,217 @@ static int ElementsInBuffer(const gl::VertexAttribute &attrib, unsigned int size
size = static_cast<unsigned int>(std::numeric_limits<int>::max());
}
- GLsizei stride = ComputeVertexAttributeStride(attrib);
- return (size - attrib.offset % stride + (stride - ComputeVertexAttributeTypeSize(attrib))) / stride;
+ GLsizei stride = static_cast<GLsizei>(ComputeVertexAttributeStride(attrib));
+ return (size - attrib.offset % stride +
+ (stride - static_cast<GLsizei>(ComputeVertexAttributeTypeSize(attrib)))) /
+ stride;
}
-static int StreamingBufferElementCount(const gl::VertexAttribute &attrib, int vertexDrawCount, int instanceDrawCount)
+VertexDataManager::CurrentValueState::CurrentValueState()
+ : buffer(nullptr),
+ offset(0)
{
- // For instanced rendering, we draw "instanceDrawCount" sets of "vertexDrawCount" vertices.
- //
- // A vertex attribute with a positive divisor loads one instanced vertex for every set of
- // non-instanced vertices, and the instanced vertex index advances once every "mDivisor" instances.
- if (instanceDrawCount > 0 && attrib.divisor > 0)
- {
- // When instanceDrawCount is not a multiple attrib.divisor, the division must round up.
- // For instance, with 5 non-instanced vertices and a divisor equal to 3, we need 2 instanced vertices.
- return (instanceDrawCount + attrib.divisor - 1) / attrib.divisor;
- }
+ data.FloatValues[0] = std::numeric_limits<float>::quiet_NaN();
+ data.FloatValues[1] = std::numeric_limits<float>::quiet_NaN();
+ data.FloatValues[2] = std::numeric_limits<float>::quiet_NaN();
+ data.FloatValues[3] = std::numeric_limits<float>::quiet_NaN();
+ data.Type = GL_FLOAT;
+}
- return vertexDrawCount;
+VertexDataManager::CurrentValueState::~CurrentValueState()
+{
+ SafeDelete(buffer);
}
VertexDataManager::VertexDataManager(BufferFactoryD3D *factory)
- : mFactory(factory)
+ : mFactory(factory),
+ mStreamingBuffer(nullptr),
+ // TODO(jmadill): use context caps
+ mCurrentValueCache(gl::MAX_VERTEX_ATTRIBS)
{
- for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
- {
- mCurrentValue[i].FloatValues[0] = std::numeric_limits<float>::quiet_NaN();
- mCurrentValue[i].FloatValues[1] = std::numeric_limits<float>::quiet_NaN();
- mCurrentValue[i].FloatValues[2] = std::numeric_limits<float>::quiet_NaN();
- mCurrentValue[i].FloatValues[3] = std::numeric_limits<float>::quiet_NaN();
- mCurrentValue[i].Type = GL_FLOAT;
- mCurrentValueBuffer[i] = NULL;
- mCurrentValueOffsets[i] = 0;
- }
-
mStreamingBuffer = new StreamingVertexBufferInterface(factory, INITIAL_STREAM_BUFFER_SIZE);
if (!mStreamingBuffer)
{
ERR("Failed to allocate the streaming vertex buffer.");
}
+
+ // TODO(jmadill): use context caps
+ mActiveEnabledAttributes.reserve(gl::MAX_VERTEX_ATTRIBS);
+ mActiveDisabledAttributes.reserve(gl::MAX_VERTEX_ATTRIBS);
}
VertexDataManager::~VertexDataManager()
{
- delete mStreamingBuffer;
-
- for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
- {
- delete mCurrentValueBuffer[i];
- }
+ SafeDelete(mStreamingBuffer);
}
void VertexDataManager::hintUnmapAllResources(const std::vector<gl::VertexAttribute> &vertexAttributes)
{
mStreamingBuffer->getVertexBuffer()->hintUnmapResource();
- for (size_t i = 0; i < vertexAttributes.size(); i++)
+ for (const TranslatedAttribute *translated : mActiveEnabledAttributes)
{
- const gl::VertexAttribute &attrib = vertexAttributes[i];
- if (attrib.enabled)
+ gl::Buffer *buffer = translated->attribute->buffer.get();
+ BufferD3D *storage = buffer ? GetImplAs<BufferD3D>(buffer) : nullptr;
+ StaticVertexBufferInterface *staticBuffer =
+ storage
+ ? storage->getStaticVertexBuffer(*translated->attribute, D3D_BUFFER_DO_NOT_CREATE)
+ : nullptr;
+
+ if (staticBuffer)
{
- gl::Buffer *buffer = attrib.buffer.get();
- BufferD3D *storage = buffer ? GetImplAs<BufferD3D>(buffer) : NULL;
- StaticVertexBufferInterface *staticBuffer = storage ? storage->getStaticVertexBuffer() : NULL;
+ // Commit all the static vertex buffers. This fixes them in size/contents, and forces
+ // ANGLE to use a new static buffer (or recreate the static buffers) next time
+ staticBuffer->commit();
- if (staticBuffer)
- {
- staticBuffer->getVertexBuffer()->hintUnmapResource();
- }
+ staticBuffer->getVertexBuffer()->hintUnmapResource();
}
}
- for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
+ for (auto &currentValue : mCurrentValueCache)
{
- if (mCurrentValueBuffer[i] != NULL)
+ if (currentValue.buffer != nullptr)
{
- mCurrentValueBuffer[i]->getVertexBuffer()->hintUnmapResource();
+ currentValue.buffer->getVertexBuffer()->hintUnmapResource();
}
}
}
-gl::Error VertexDataManager::prepareVertexData(const gl::State &state, GLint start, GLsizei count,
- TranslatedAttribute *translated, GLsizei instances)
+gl::Error VertexDataManager::prepareVertexData(const gl::State &state,
+ GLint start,
+ GLsizei count,
+ std::vector<TranslatedAttribute> *translatedAttribs,
+ GLsizei instances)
{
if (!mStreamingBuffer)
{
return gl::Error(GL_OUT_OF_MEMORY, "Internal streaming vertex buffer is unexpectedly NULL.");
}
+ // Compute active enabled and active disable attributes, for speed.
+ // TODO(jmadill): don't recompute if there was no state change
const gl::VertexArray *vertexArray = state.getVertexArray();
- const std::vector<gl::VertexAttribute> &vertexAttributes = vertexArray->getVertexAttributes();
+ const gl::Program *program = state.getProgram();
+ const auto &vertexAttributes = vertexArray->getVertexAttributes();
+
+ mActiveEnabledAttributes.clear();
+ mActiveDisabledAttributes.clear();
+ translatedAttribs->clear();
- // Invalidate static buffers that don't contain matching attributes
- for (int attributeIndex = 0; attributeIndex < gl::MAX_VERTEX_ATTRIBS; attributeIndex++)
+ for (size_t attribIndex = 0; attribIndex < vertexAttributes.size(); ++attribIndex)
{
- translated[attributeIndex].active = (state.getProgram()->getSemanticIndex(attributeIndex) != -1);
- if (translated[attributeIndex].active && vertexAttributes[attributeIndex].enabled)
+ if (program->isAttribLocationActive(attribIndex))
{
- invalidateMatchingStaticData(vertexAttributes[attributeIndex], state.getVertexAttribCurrentValue(attributeIndex));
+ // Resize automatically puts in empty attribs
+ translatedAttribs->resize(attribIndex + 1);
+
+ TranslatedAttribute *translated = &(*translatedAttribs)[attribIndex];
+
+ // Record the attribute now
+ translated->active = true;
+ translated->attribute = &vertexAttributes[attribIndex];
+ translated->currentValueType =
+ state.getVertexAttribCurrentValue(static_cast<unsigned int>(attribIndex)).Type;
+ translated->divisor = vertexAttributes[attribIndex].divisor;
+
+ if (vertexAttributes[attribIndex].enabled)
+ {
+ mActiveEnabledAttributes.push_back(translated);
+
+ gl::Buffer *buffer = vertexAttributes[attribIndex].buffer.get();
+ if (buffer)
+ {
+ // Also reinitialize static buffers which didn't contain matching data
+ // last time they were used
+ BufferD3D *bufferImpl = GetImplAs<BufferD3D>(buffer);
+ bufferImpl->reinitOutOfDateStaticData();
+ }
+ }
+ else
+ {
+ mActiveDisabledAttributes.push_back(attribIndex);
+ }
}
}
// Reserve the required space in the buffers
- for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
+ for (const TranslatedAttribute *activeAttrib : mActiveEnabledAttributes)
{
- if (translated[i].active && vertexAttributes[i].enabled)
+ gl::Error error = reserveSpaceForAttrib(*activeAttrib, count, instances);
+ if (error.isError())
{
- gl::Error error = reserveSpaceForAttrib(vertexAttributes[i], state.getVertexAttribCurrentValue(i), count, instances);
- if (error.isError())
- {
- return error;
- }
+ return error;
}
}
// Perform the vertex data translations
- for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
+ for (TranslatedAttribute *activeAttrib : mActiveEnabledAttributes)
{
- const gl::VertexAttribute &curAttrib = vertexAttributes[i];
- if (translated[i].active)
- {
- if (curAttrib.enabled)
- {
- gl::Error error = storeAttribute(curAttrib, state.getVertexAttribCurrentValue(i),
- &translated[i], start, count, instances);
+ gl::Error error = storeAttribute(activeAttrib, start, count, instances);
- if (error.isError())
- {
- hintUnmapAllResources(vertexAttributes);
- return error;
- }
- }
- else
- {
- if (!mCurrentValueBuffer[i])
- {
- mCurrentValueBuffer[i] = new StreamingVertexBufferInterface(mFactory, CONSTANT_VERTEX_BUFFER_SIZE);
- }
-
- gl::Error error = storeCurrentValue(curAttrib, state.getVertexAttribCurrentValue(i), &translated[i],
- &mCurrentValue[i], &mCurrentValueOffsets[i],
- mCurrentValueBuffer[i]);
- if (error.isError())
- {
- hintUnmapAllResources(vertexAttributes);
- return error;
- }
- }
+ if (error.isError())
+ {
+ hintUnmapAllResources(vertexAttributes);
+ return error;
}
}
- // Hint to unmap all the resources
- hintUnmapAllResources(vertexAttributes);
-
- for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
+ for (size_t attribIndex : mActiveDisabledAttributes)
{
- const gl::VertexAttribute &curAttrib = vertexAttributes[i];
- if (translated[i].active && curAttrib.enabled)
+ if (mCurrentValueCache[attribIndex].buffer == nullptr)
{
- gl::Buffer *buffer = curAttrib.buffer.get();
+ mCurrentValueCache[attribIndex].buffer = new StreamingVertexBufferInterface(mFactory, CONSTANT_VERTEX_BUFFER_SIZE);
+ }
- if (buffer)
- {
- BufferD3D *bufferImpl = GetImplAs<BufferD3D>(buffer);
- bufferImpl->promoteStaticUsage(count * ComputeVertexAttributeTypeSize(curAttrib));
- }
+ gl::Error error = storeCurrentValue(
+ state.getVertexAttribCurrentValue(static_cast<unsigned int>(attribIndex)),
+ &(*translatedAttribs)[attribIndex], &mCurrentValueCache[attribIndex]);
+ if (error.isError())
+ {
+ hintUnmapAllResources(vertexAttributes);
+ return error;
}
}
- return gl::Error(GL_NO_ERROR);
-}
-
-void VertexDataManager::invalidateMatchingStaticData(const gl::VertexAttribute &attrib,
- const gl::VertexAttribCurrentValueData &currentValue) const
-{
- gl::Buffer *buffer = attrib.buffer.get();
+ // Hint to unmap all the resources
+ hintUnmapAllResources(vertexAttributes);
- if (buffer)
+ for (const TranslatedAttribute *activeAttrib : mActiveEnabledAttributes)
{
- BufferD3D *bufferImpl = GetImplAs<BufferD3D>(buffer);
- StaticVertexBufferInterface *staticBuffer = bufferImpl->getStaticVertexBuffer();
+ gl::Buffer *buffer = activeAttrib->attribute->buffer.get();
- if (staticBuffer &&
- staticBuffer->getBufferSize() > 0 &&
- !staticBuffer->lookupAttribute(attrib, NULL) &&
- !staticBuffer->directStoragePossible(attrib, currentValue))
+ if (buffer)
{
- bufferImpl->invalidateStaticData();
+ BufferD3D *bufferD3D = GetImplAs<BufferD3D>(buffer);
+ size_t typeSize = ComputeVertexAttributeTypeSize(*activeAttrib->attribute);
+ bufferD3D->promoteStaticUsage(count * static_cast<int>(typeSize));
}
}
+
+ return gl::Error(GL_NO_ERROR);
}
-gl::Error VertexDataManager::reserveSpaceForAttrib(const gl::VertexAttribute &attrib,
- const gl::VertexAttribCurrentValueData &currentValue,
+gl::Error VertexDataManager::reserveSpaceForAttrib(const TranslatedAttribute &translatedAttrib,
GLsizei count,
GLsizei instances) const
{
+ const gl::VertexAttribute &attrib = *translatedAttrib.attribute;
gl::Buffer *buffer = attrib.buffer.get();
BufferD3D *bufferImpl = buffer ? GetImplAs<BufferD3D>(buffer) : NULL;
- StaticVertexBufferInterface *staticBuffer = bufferImpl ? bufferImpl->getStaticVertexBuffer() : NULL;
+ StaticVertexBufferInterface *staticBuffer =
+ bufferImpl ? bufferImpl->getStaticVertexBuffer(attrib, D3D_BUFFER_CREATE_IF_NECESSARY)
+ : NULL;
VertexBufferInterface *vertexBuffer = staticBuffer ? staticBuffer : static_cast<VertexBufferInterface*>(mStreamingBuffer);
- if (!vertexBuffer->directStoragePossible(attrib, currentValue))
+ if (!vertexBuffer->directStoragePossible(attrib, translatedAttrib.currentValueType))
{
if (staticBuffer)
{
if (staticBuffer->getBufferSize() == 0)
{
- int totalCount = ElementsInBuffer(attrib, bufferImpl->getSize());
+ int totalCount =
+ ElementsInBuffer(attrib, static_cast<unsigned int>(bufferImpl->getSize()));
gl::Error error = staticBuffer->reserveVertexSpace(attrib, totalCount, 0);
if (error.isError())
{
@@ -253,10 +255,13 @@ gl::Error VertexDataManager::reserveSpaceForAttrib(const gl::VertexAttribute &at
}
else
{
- int totalCount = StreamingBufferElementCount(attrib, count, instances);
- ASSERT(!bufferImpl || ElementsInBuffer(attrib, bufferImpl->getSize()) >= totalCount);
+ size_t totalCount = ComputeVertexAttributeElementCount(attrib, count, instances);
+ ASSERT(!bufferImpl ||
+ ElementsInBuffer(attrib, static_cast<unsigned int>(bufferImpl->getSize())) >=
+ static_cast<int>(totalCount));
- gl::Error error = mStreamingBuffer->reserveVertexSpace(attrib, totalCount, instances);
+ gl::Error error = mStreamingBuffer->reserveVertexSpace(
+ attrib, static_cast<GLsizei>(totalCount), instances);
if (error.isError())
{
return error;
@@ -267,33 +272,59 @@ gl::Error VertexDataManager::reserveSpaceForAttrib(const gl::VertexAttribute &at
return gl::Error(GL_NO_ERROR);
}
-gl::Error VertexDataManager::storeAttribute(const gl::VertexAttribute &attrib,
- const gl::VertexAttribCurrentValueData &currentValue,
- TranslatedAttribute *translated,
+gl::Error VertexDataManager::storeAttribute(TranslatedAttribute *translated,
GLint start,
GLsizei count,
GLsizei instances)
{
+ const gl::VertexAttribute &attrib = *translated->attribute;
+
gl::Buffer *buffer = attrib.buffer.get();
ASSERT(buffer || attrib.pointer);
+ ASSERT(attrib.enabled);
BufferD3D *storage = buffer ? GetImplAs<BufferD3D>(buffer) : NULL;
- StaticVertexBufferInterface *staticBuffer = storage ? storage->getStaticVertexBuffer() : NULL;
+ StaticVertexBufferInterface *staticBuffer =
+ storage ? storage->getStaticVertexBuffer(attrib, D3D_BUFFER_DO_NOT_CREATE) : NULL;
VertexBufferInterface *vertexBuffer = staticBuffer ? staticBuffer : static_cast<VertexBufferInterface*>(mStreamingBuffer);
- bool directStorage = vertexBuffer->directStoragePossible(attrib, currentValue);
-
- unsigned int streamOffset = 0;
- unsigned int outputElementSize = 0;
+ bool directStorage = vertexBuffer->directStoragePossible(attrib, translated->currentValueType);
// Instanced vertices do not apply the 'start' offset
- GLint firstVertexIndex = (instances > 0 && attrib.divisor > 0 ? 0 : start);
+ GLint firstVertexIndex = (attrib.divisor > 0 ? 0 : start);
+
+ translated->vertexBuffer = vertexBuffer->getVertexBuffer();
if (directStorage)
{
- outputElementSize = ComputeVertexAttributeStride(attrib);
- streamOffset = attrib.offset + outputElementSize * firstVertexIndex;
+ translated->storage = storage;
+ translated->serial = storage->getSerial();
+ translated->stride = static_cast<unsigned int>(ComputeVertexAttributeStride(attrib));
+ translated->offset = static_cast<unsigned int>(attrib.offset + translated->stride * firstVertexIndex);
+
+ return gl::Error(GL_NO_ERROR);
+ }
+
+ // Compute source data pointer
+ const uint8_t *sourceData = nullptr;
+
+ if (buffer)
+ {
+ gl::Error error = storage->getData(&sourceData);
+ if (error.isError())
+ {
+ return error;
+ }
+ sourceData += static_cast<int>(attrib.offset);
+ }
+ else
+ {
+ sourceData = static_cast<const uint8_t*>(attrib.pointer);
}
- else if (staticBuffer)
+
+ unsigned int streamOffset = 0;
+ unsigned int outputElementSize = 0;
+
+ if (staticBuffer)
{
gl::Error error = staticBuffer->getVertexBuffer()->getSpaceRequired(attrib, 1, 0, &outputElementSize);
if (error.isError())
@@ -304,19 +335,30 @@ gl::Error VertexDataManager::storeAttribute(const gl::VertexAttribute &attrib,
if (!staticBuffer->lookupAttribute(attrib, &streamOffset))
{
// Convert the entire buffer
- int totalCount = ElementsInBuffer(attrib, storage->getSize());
- int startIndex = attrib.offset / ComputeVertexAttributeStride(attrib);
-
- error = staticBuffer->storeVertexAttributes(attrib, currentValue, -startIndex, totalCount,
- 0, &streamOffset);
+ int totalCount =
+ ElementsInBuffer(attrib, static_cast<unsigned int>(storage->getSize()));
+ int startIndex = static_cast<int>(attrib.offset) /
+ static_cast<int>(ComputeVertexAttributeStride(attrib));
+
+ error = staticBuffer->storeVertexAttributes(attrib,
+ translated->currentValueType,
+ -startIndex,
+ totalCount,
+ 0,
+ &streamOffset,
+ sourceData);
if (error.isError())
{
return error;
}
}
- unsigned int firstElementOffset = (attrib.offset / ComputeVertexAttributeStride(attrib)) * outputElementSize;
- unsigned int startOffset = (instances == 0 || attrib.divisor == 0) ? firstVertexIndex * outputElementSize : 0;
+ unsigned int firstElementOffset =
+ (static_cast<unsigned int>(attrib.offset) /
+ static_cast<unsigned int>(ComputeVertexAttributeStride(attrib))) *
+ outputElementSize;
+ ASSERT(attrib.divisor == 0 || firstVertexIndex == 0);
+ unsigned int startOffset = firstVertexIndex * outputElementSize;
if (streamOffset + firstElementOffset + startOffset < streamOffset)
{
return gl::Error(GL_OUT_OF_MEMORY);
@@ -326,69 +368,63 @@ gl::Error VertexDataManager::storeAttribute(const gl::VertexAttribute &attrib,
}
else
{
- int totalCount = StreamingBufferElementCount(attrib, count, instances);
+ size_t totalCount = ComputeVertexAttributeElementCount(attrib, count, instances);
gl::Error error = mStreamingBuffer->getVertexBuffer()->getSpaceRequired(attrib, 1, 0, &outputElementSize);
if (error.isError())
{
return error;
}
- error = mStreamingBuffer->storeVertexAttributes(attrib, currentValue, firstVertexIndex,
- totalCount, instances, &streamOffset);
+ error = mStreamingBuffer->storeVertexAttributes(
+ attrib, translated->currentValueType, firstVertexIndex,
+ static_cast<GLsizei>(totalCount), instances, &streamOffset, sourceData);
if (error.isError())
{
return error;
}
}
- translated->storage = directStorage ? storage : NULL;
- translated->vertexBuffer = vertexBuffer->getVertexBuffer();
- translated->serial = directStorage ? storage->getSerial() : vertexBuffer->getSerial();
- translated->divisor = attrib.divisor;
-
- translated->attribute = &attrib;
- translated->currentValueType = currentValue.Type;
+ translated->storage = nullptr;
+ translated->serial = vertexBuffer->getSerial();
translated->stride = outputElementSize;
translated->offset = streamOffset;
return gl::Error(GL_NO_ERROR);
}
-gl::Error VertexDataManager::storeCurrentValue(const gl::VertexAttribute &attrib,
- const gl::VertexAttribCurrentValueData &currentValue,
+gl::Error VertexDataManager::storeCurrentValue(const gl::VertexAttribCurrentValueData &currentValue,
TranslatedAttribute *translated,
- gl::VertexAttribCurrentValueData *cachedValue,
- size_t *cachedOffset,
- StreamingVertexBufferInterface *buffer)
+ CurrentValueState *cachedState)
{
- if (*cachedValue != currentValue)
+ if (cachedState->data != currentValue)
{
- gl::Error error = buffer->reserveVertexSpace(attrib, 1, 0);
+ const gl::VertexAttribute &attrib = *translated->attribute;
+
+ gl::Error error = cachedState->buffer->reserveVertexSpace(attrib, 1, 0);
if (error.isError())
{
return error;
}
+ const uint8_t *sourceData = reinterpret_cast<const uint8_t*>(currentValue.FloatValues);
unsigned int streamOffset;
- error = buffer->storeVertexAttributes(attrib, currentValue, 0, 1, 0, &streamOffset);
+ error = cachedState->buffer->storeVertexAttributes(attrib, currentValue.Type, 0, 1, 0, &streamOffset, sourceData);
if (error.isError())
{
return error;
}
- *cachedValue = currentValue;
- *cachedOffset = streamOffset;
+ cachedState->data = currentValue;
+ cachedState->offset = streamOffset;
}
translated->storage = NULL;
- translated->vertexBuffer = buffer->getVertexBuffer();
- translated->serial = buffer->getSerial();
+ translated->vertexBuffer = cachedState->buffer->getVertexBuffer();
+ translated->serial = cachedState->buffer->getSerial();
translated->divisor = 0;
- translated->attribute = &attrib;
- translated->currentValueType = currentValue.Type;
translated->stride = 0;
- translated->offset = *cachedOffset;
+ translated->offset = static_cast<unsigned int>(cachedState->offset);
return gl::Error(GL_NO_ERROR);
}
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexDataManager.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexDataManager.h
index 898ed340b8..fb349c4cc2 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexDataManager.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexDataManager.h
@@ -30,9 +30,18 @@ class VertexBuffer;
struct TranslatedAttribute
{
- TranslatedAttribute() : active(false), attribute(NULL), currentValueType(GL_NONE),
- offset(0), stride(0), vertexBuffer(NULL), storage(NULL),
- serial(0), divisor(0) {};
+ TranslatedAttribute()
+ : active(false),
+ attribute(NULL),
+ currentValueType(GL_NONE),
+ offset(0),
+ stride(0),
+ vertexBuffer(NULL),
+ storage(NULL),
+ serial(0),
+ divisor(0)
+ {}
+
bool active;
const gl::VertexAttribute *attribute;
@@ -52,42 +61,46 @@ class VertexDataManager : angle::NonCopyable
VertexDataManager(BufferFactoryD3D *factory);
virtual ~VertexDataManager();
- gl::Error prepareVertexData(const gl::State &state, GLint start, GLsizei count,
- TranslatedAttribute *outAttribs, GLsizei instances);
+ gl::Error prepareVertexData(const gl::State &state,
+ GLint start,
+ GLsizei count,
+ std::vector<TranslatedAttribute> *translatedAttribs,
+ GLsizei instances);
private:
- gl::Error reserveSpaceForAttrib(const gl::VertexAttribute &attrib,
- const gl::VertexAttribCurrentValueData &currentValue,
+ struct CurrentValueState
+ {
+ CurrentValueState();
+ ~CurrentValueState();
+
+ StreamingVertexBufferInterface *buffer;
+ gl::VertexAttribCurrentValueData data;
+ size_t offset;
+ };
+
+ gl::Error reserveSpaceForAttrib(const TranslatedAttribute &translatedAttrib,
GLsizei count,
GLsizei instances) const;
- void invalidateMatchingStaticData(const gl::VertexAttribute &attrib,
- const gl::VertexAttribCurrentValueData &currentValue) const;
-
- gl::Error storeAttribute(const gl::VertexAttribute &attrib,
- const gl::VertexAttribCurrentValueData &currentValue,
- TranslatedAttribute *translated,
+ gl::Error storeAttribute(TranslatedAttribute *translated,
GLint start,
GLsizei count,
GLsizei instances);
- gl::Error storeCurrentValue(const gl::VertexAttribute &attrib,
- const gl::VertexAttribCurrentValueData &currentValue,
+ gl::Error storeCurrentValue(const gl::VertexAttribCurrentValueData &currentValue,
TranslatedAttribute *translated,
- gl::VertexAttribCurrentValueData *cachedValue,
- size_t *cachedOffset,
- StreamingVertexBufferInterface *buffer);
+ CurrentValueState *cachedState);
void hintUnmapAllResources(const std::vector<gl::VertexAttribute> &vertexAttributes);
BufferFactoryD3D *const mFactory;
StreamingVertexBufferInterface *mStreamingBuffer;
+ std::vector<CurrentValueState> mCurrentValueCache;
- gl::VertexAttribCurrentValueData mCurrentValue[gl::MAX_VERTEX_ATTRIBS];
-
- StreamingVertexBufferInterface *mCurrentValueBuffer[gl::MAX_VERTEX_ATTRIBS];
- std::size_t mCurrentValueOffsets[gl::MAX_VERTEX_ATTRIBS];
+ // Cache variables
+ std::vector<TranslatedAttribute *> mActiveEnabledAttributes;
+ std::vector<size_t> mActiveDisabledAttributes;
};
}
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/WorkaroundsD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/WorkaroundsD3D.h
new file mode 100644
index 0000000000..58f65f6496
--- /dev/null
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/WorkaroundsD3D.h
@@ -0,0 +1,66 @@
+//
+// 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.
+//
+
+// WorkaroundsD3D.h: Workarounds for D3D driver bugs and other issues.
+
+#ifndef LIBANGLE_RENDERER_D3D_WORKAROUNDSD3D_H_
+#define LIBANGLE_RENDERER_D3D_WORKAROUNDSD3D_H_
+
+// TODO(jmadill,zmo,geofflang): make a workarounds library that can operate
+// independent of ANGLE's renderer. Workarounds should also be accessible
+// outside of the Renderer.
+
+namespace rx
+{
+struct D3DCompilerWorkarounds
+{
+ D3DCompilerWorkarounds()
+ : skipOptimization(false), useMaxOptimization(false), enableIEEEStrictness(false)
+ {
+ }
+
+ bool skipOptimization;
+ bool useMaxOptimization;
+
+ // IEEE strictness needs to be enabled for NANs to work.
+ bool enableIEEEStrictness;
+};
+
+struct WorkaroundsD3D
+{
+ WorkaroundsD3D()
+ : mrtPerfWorkaround(false),
+ setDataFasterThanImageUpload(false),
+ zeroMaxLodWorkaround(false),
+ useInstancedPointSpriteEmulation(false)
+ {
+ }
+
+ // On some systems, having extra rendertargets than necessary slows down the shader.
+ // We can fix this by optimizing those out of the shader. At the same time, we can
+ // work around a bug on some nVidia drivers that they ignore "null" render targets
+ // in D3D11, by compacting the active color attachments list to omit null entries.
+ bool mrtPerfWorkaround;
+
+ bool setDataFasterThanImageUpload;
+
+ // Some renderers can't disable mipmaps on a mipmapped texture (i.e. solely sample from level
+ // zero, and ignore the other levels). D3D11 Feature Level 10+ does this by setting MaxLOD to
+ // 0.0f in the Sampler state. D3D9 sets D3DSAMP_MIPFILTER to D3DTEXF_NONE. There is no
+ // equivalent to this in D3D11 Feature Level 9_3. This causes problems when (for example) an
+ // application creates a mipmapped texture2D, but sets GL_TEXTURE_MIN_FILTER to GL_NEAREST
+ // (i.e disables mipmaps). To work around this, D3D11 FL9_3 has to create two copies of the
+ // texture. The textures' level zeros are identical, but only one texture has mips.
+ bool zeroMaxLodWorkaround;
+
+ // Some renderers do not support Geometry Shaders so the Geometry Shader-based PointSprite
+ // emulation will not work. To work around this, D3D11 FL9_3 has to use a different pointsprite
+ // emulation that is implemented using instanced quads.
+ bool useInstancedPointSpriteEmulation;
+};
+}
+
+#endif // LIBANGLE_RENDERER_D3D_WORKAROUNDSD3D_H_
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Blit11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Blit11.cpp
index e38b61709f..e951e13408 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Blit11.cpp
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Blit11.cpp
@@ -10,10 +10,11 @@
#include <float.h>
+#include "libANGLE/formatutils.h"
#include "libANGLE/renderer/d3d/d3d11/Renderer11.h"
#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h"
#include "libANGLE/renderer/d3d/d3d11/formatutils11.h"
-#include "libANGLE/formatutils.h"
+#include "third_party/trace_event/trace_event.h"
#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthrough2d11vs.h"
#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughdepth2d11ps.h"
@@ -62,7 +63,10 @@
namespace rx
{
-static DXGI_FORMAT GetTextureFormat(ID3D11Resource *resource)
+namespace
+{
+
+DXGI_FORMAT GetTextureFormat(ID3D11Resource *resource)
{
ID3D11Texture2D *texture = d3d11::DynamicCastComObject<ID3D11Texture2D>(resource);
if (!texture)
@@ -78,9 +82,9 @@ static DXGI_FORMAT GetTextureFormat(ID3D11Resource *resource)
return desc.Format;
}
-static ID3D11Resource *CreateStagingTexture(ID3D11Device *device, ID3D11DeviceContext *context,
- ID3D11Resource *source, unsigned int subresource,
- const gl::Extents &size, unsigned int cpuAccessFlags)
+ID3D11Resource *CreateStagingTexture(ID3D11Device *device, ID3D11DeviceContext *context,
+ ID3D11Resource *source, unsigned int subresource,
+ const gl::Extents &size, unsigned int cpuAccessFlags)
{
D3D11_TEXTURE2D_DESC stagingDesc;
stagingDesc.Width = size.width;
@@ -95,23 +99,23 @@ static ID3D11Resource *CreateStagingTexture(ID3D11Device *device, ID3D11DeviceCo
stagingDesc.MiscFlags = 0;
stagingDesc.BindFlags = 0;
- ID3D11Texture2D *stagingTexture = NULL;
- HRESULT result = device->CreateTexture2D(&stagingDesc, NULL, &stagingTexture);
+ ID3D11Texture2D *stagingTexture = nullptr;
+ HRESULT result = device->CreateTexture2D(&stagingDesc, nullptr, &stagingTexture);
if (FAILED(result))
{
ERR("Failed to create staging texture for depth stencil blit. HRESULT: 0x%X.", result);
- return NULL;
+ return nullptr;
}
- context->CopySubresourceRegion(stagingTexture, 0, 0, 0, 0, source, subresource, NULL);
+ context->CopySubresourceRegion(stagingTexture, 0, 0, 0, 0, source, subresource, nullptr);
return stagingTexture;
}
-inline static void GenerateVertexCoords(const gl::Box &sourceArea, const gl::Extents &sourceSize,
- const gl::Box &destArea, const gl::Extents &destSize,
- float *x1, float *y1, float *x2, float *y2,
- float *u1, float *v1, float *u2, float *v2)
+inline void GenerateVertexCoords(const gl::Box &sourceArea, const gl::Extents &sourceSize,
+ const gl::Box &destArea, const gl::Extents &destSize,
+ float *x1, float *y1, float *x2, float *y2,
+ float *u1, float *v1, float *u2, float *v2)
{
*x1 = (destArea.x / float(destSize.width)) * 2.0f - 1.0f;
*y1 = ((destSize.height - destArea.y - destArea.height) / float(destSize.height)) * 2.0f - 1.0f;
@@ -124,10 +128,10 @@ inline static void GenerateVertexCoords(const gl::Box &sourceArea, const gl::Ext
*v2 = (sourceArea.y + sourceArea.height) / float(sourceSize.height);
}
-static void Write2DVertices(const gl::Box &sourceArea, const gl::Extents &sourceSize,
- const gl::Box &destArea, const gl::Extents &destSize,
- void *outVertices, unsigned int *outStride, unsigned int *outVertexCount,
- D3D11_PRIMITIVE_TOPOLOGY *outTopology)
+void Write2DVertices(const gl::Box &sourceArea, const gl::Extents &sourceSize,
+ const gl::Box &destArea, const gl::Extents &destSize,
+ void *outVertices, unsigned int *outStride, unsigned int *outVertexCount,
+ D3D11_PRIMITIVE_TOPOLOGY *outTopology)
{
float x1, y1, x2, y2, u1, v1, u2, v2;
GenerateVertexCoords(sourceArea, sourceSize, destArea, destSize, &x1, &y1, &x2, &y2, &u1, &v1, &u2, &v2);
@@ -144,10 +148,10 @@ static void Write2DVertices(const gl::Box &sourceArea, const gl::Extents &source
*outTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP;
}
-static void Write3DVertices(const gl::Box &sourceArea, const gl::Extents &sourceSize,
- const gl::Box &destArea, const gl::Extents &destSize,
- void *outVertices, unsigned int *outStride, unsigned int *outVertexCount,
- D3D11_PRIMITIVE_TOPOLOGY *outTopology)
+void Write3DVertices(const gl::Box &sourceArea, const gl::Extents &sourceSize,
+ const gl::Box &destArea, const gl::Extents &destSize,
+ void *outVertices, unsigned int *outStride, unsigned int *outVertexCount,
+ D3D11_PRIMITIVE_TOPOLOGY *outTopology)
{
ASSERT(sourceSize.depth > 0 && destSize.depth > 0);
@@ -174,28 +178,132 @@ static void Write3DVertices(const gl::Box &sourceArea, const gl::Extents &source
*outTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
}
+inline unsigned int GetSwizzleIndex(GLenum swizzle)
+{
+ unsigned int colorIndex = 0;
+
+ switch (swizzle)
+ {
+ case GL_RED: colorIndex = 0; break;
+ case GL_GREEN: colorIndex = 1; break;
+ case GL_BLUE: colorIndex = 2; break;
+ case GL_ALPHA: colorIndex = 3; break;
+ case GL_ZERO: colorIndex = 4; break;
+ case GL_ONE: colorIndex = 5; break;
+ default: UNREACHABLE(); break;
+ }
+
+ return colorIndex;
+}
+
+D3D11_BLEND_DESC GetAlphaMaskBlendStateDesc()
+{
+ D3D11_BLEND_DESC desc;
+ memset(&desc, 0, sizeof(desc));
+ desc.RenderTarget[0].BlendEnable = TRUE;
+ desc.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE;
+ desc.RenderTarget[0].DestBlend = D3D11_BLEND_ZERO;
+ desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
+ desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ZERO;
+ desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
+ desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
+ desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_RED |
+ D3D11_COLOR_WRITE_ENABLE_GREEN |
+ D3D11_COLOR_WRITE_ENABLE_BLUE;
+ return desc;
+}
+
+D3D11_INPUT_ELEMENT_DESC quad2DLayout[] =
+{
+ { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
+ { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 8, D3D11_INPUT_PER_VERTEX_DATA, 0 },
+};
+
+D3D11_INPUT_ELEMENT_DESC quad3DLayout[] =
+{
+ { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
+ { "LAYER", 0, DXGI_FORMAT_R32_UINT, 0, 8, D3D11_INPUT_PER_VERTEX_DATA, 0 },
+ { "TEXCOORD", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
+};
+
+} // namespace
+
Blit11::Blit11(Renderer11 *renderer)
- : mRenderer(renderer), mBlitShaderMap(compareBlitParameters), mSwizzleShaderMap(compareSwizzleParameters),
- mVertexBuffer(NULL), mPointSampler(NULL), mLinearSampler(NULL), mScissorEnabledRasterizerState(NULL),
- mScissorDisabledRasterizerState(NULL), mDepthStencilState(NULL),
- mQuad2DIL(NULL), mQuad2DVS(NULL), mDepthPS(NULL),
- mQuad3DIL(NULL), mQuad3DVS(NULL), mQuad3DGS(NULL),
- mSwizzleCB(NULL)
+ : mRenderer(renderer),
+ mResourcesInitialized(false),
+ mVertexBuffer(nullptr),
+ mPointSampler(nullptr),
+ mLinearSampler(nullptr),
+ mScissorEnabledRasterizerState(nullptr),
+ mScissorDisabledRasterizerState(nullptr),
+ mDepthStencilState(nullptr),
+ mQuad2DIL(quad2DLayout,
+ ArraySize(quad2DLayout),
+ g_VS_Passthrough2D,
+ ArraySize(g_VS_Passthrough2D),
+ "Blit11 2D input layout"),
+ mQuad2DVS(g_VS_Passthrough2D, ArraySize(g_VS_Passthrough2D), "Blit11 2D vertex shader"),
+ mDepthPS(g_PS_PassthroughDepth2D,
+ ArraySize(g_PS_PassthroughDepth2D),
+ "Blit11 2D depth pixel shader"),
+ mQuad3DIL(quad3DLayout,
+ ArraySize(quad3DLayout),
+ g_VS_Passthrough3D,
+ ArraySize(g_VS_Passthrough3D),
+ "Blit11 3D input layout"),
+ mQuad3DVS(g_VS_Passthrough3D, ArraySize(g_VS_Passthrough3D), "Blit11 3D vertex shader"),
+ mQuad3DGS(g_GS_Passthrough3D, ArraySize(g_GS_Passthrough3D), "Blit11 3D geometry shader"),
+ mAlphaMaskBlendState(GetAlphaMaskBlendStateDesc(), "Blit11 Alpha Mask Blend"),
+ mSwizzleCB(nullptr)
+{
+}
+
+Blit11::~Blit11()
+{
+ freeResources();
+
+ mQuad2DIL.release();
+ mQuad2DVS.release();
+ mDepthPS.release();
+
+ mQuad3DIL.release();
+ mQuad3DVS.release();
+ mQuad3DGS.release();
+
+ clearShaderMap();
+}
+
+gl::Error Blit11::initResources()
{
+ if (mResourcesInitialized)
+ {
+ return gl::Error(GL_NO_ERROR);
+ }
+
+ TRACE_EVENT0("gpu.angle", "Blit11::initResources");
+
HRESULT result;
ID3D11Device *device = mRenderer->getDevice();
D3D11_BUFFER_DESC vbDesc;
- vbDesc.ByteWidth = std::max(sizeof(d3d11::PositionLayerTexCoord3DVertex), sizeof(d3d11::PositionTexCoordVertex)) *
- 6 * renderer->getRendererCaps().max3DTextureSize;
+ vbDesc.ByteWidth =
+ static_cast<unsigned int>(std::max(sizeof(d3d11::PositionLayerTexCoord3DVertex),
+ sizeof(d3d11::PositionTexCoordVertex)) *
+ 6 * mRenderer->getRendererCaps().max3DTextureSize);
vbDesc.Usage = D3D11_USAGE_DYNAMIC;
vbDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
vbDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
vbDesc.MiscFlags = 0;
vbDesc.StructureByteStride = 0;
- result = device->CreateBuffer(&vbDesc, NULL, &mVertexBuffer);
+ result = device->CreateBuffer(&vbDesc, nullptr, &mVertexBuffer);
ASSERT(SUCCEEDED(result));
+ if (FAILED(result))
+ {
+ freeResources();
+ return gl::Error(GL_OUT_OF_MEMORY, "Failed to create blit vertex buffer, HRESULT: 0x%X",
+ result);
+ }
d3d11::SetDebugName(mVertexBuffer, "Blit11 vertex buffer");
D3D11_SAMPLER_DESC pointSamplerDesc;
@@ -215,6 +323,12 @@ Blit11::Blit11(Renderer11 *renderer)
result = device->CreateSamplerState(&pointSamplerDesc, &mPointSampler);
ASSERT(SUCCEEDED(result));
+ if (FAILED(result))
+ {
+ freeResources();
+ return gl::Error(GL_OUT_OF_MEMORY,
+ "Failed to create blit point sampler state, HRESULT: 0x%X", result);
+ }
d3d11::SetDebugName(mPointSampler, "Blit11 point sampler");
D3D11_SAMPLER_DESC linearSamplerDesc;
@@ -234,6 +348,12 @@ Blit11::Blit11(Renderer11 *renderer)
result = device->CreateSamplerState(&linearSamplerDesc, &mLinearSampler);
ASSERT(SUCCEEDED(result));
+ if (FAILED(result))
+ {
+ freeResources();
+ return gl::Error(GL_OUT_OF_MEMORY,
+ "Failed to create blit linear sampler state, HRESULT: 0x%X", result);
+ }
d3d11::SetDebugName(mLinearSampler, "Blit11 linear sampler");
// Use a rasterizer state that will not cull so that inverted quads will not be culled
@@ -251,11 +371,25 @@ Blit11::Blit11(Renderer11 *renderer)
rasterDesc.ScissorEnable = TRUE;
result = device->CreateRasterizerState(&rasterDesc, &mScissorEnabledRasterizerState);
ASSERT(SUCCEEDED(result));
+ if (FAILED(result))
+ {
+ freeResources();
+ return gl::Error(GL_OUT_OF_MEMORY,
+ "Failed to create blit scissoring rasterizer state, HRESULT: 0x%X",
+ result);
+ }
d3d11::SetDebugName(mScissorEnabledRasterizerState, "Blit11 scissoring rasterizer state");
rasterDesc.ScissorEnable = FALSE;
result = device->CreateRasterizerState(&rasterDesc, &mScissorDisabledRasterizerState);
ASSERT(SUCCEEDED(result));
+ if (FAILED(result))
+ {
+ freeResources();
+ return gl::Error(GL_OUT_OF_MEMORY,
+ "Failed to create blit no scissoring rasterizer state, HRESULT: 0x%X",
+ result);
+ }
d3d11::SetDebugName(mScissorDisabledRasterizerState, "Blit11 no scissoring rasterizer state");
D3D11_DEPTH_STENCIL_DESC depthStencilDesc;
@@ -276,49 +410,13 @@ Blit11::Blit11(Renderer11 *renderer)
result = device->CreateDepthStencilState(&depthStencilDesc, &mDepthStencilState);
ASSERT(SUCCEEDED(result));
- d3d11::SetDebugName(mDepthStencilState, "Blit11 depth stencil state");
-
- D3D11_INPUT_ELEMENT_DESC quad2DLayout[] =
- {
- { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
- { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 8, D3D11_INPUT_PER_VERTEX_DATA, 0 },
- };
-
- result = device->CreateInputLayout(quad2DLayout, ArraySize(quad2DLayout), g_VS_Passthrough2D, ArraySize(g_VS_Passthrough2D), &mQuad2DIL);
- ASSERT(SUCCEEDED(result));
- d3d11::SetDebugName(mQuad2DIL, "Blit11 2D input layout");
-
- result = device->CreateVertexShader(g_VS_Passthrough2D, ArraySize(g_VS_Passthrough2D), NULL, &mQuad2DVS);
- ASSERT(SUCCEEDED(result));
- d3d11::SetDebugName(mQuad2DVS, "Blit11 2D vertex shader");
-
- if (renderer->isES3Capable())
+ if (FAILED(result))
{
- result = device->CreatePixelShader(g_PS_PassthroughDepth2D, ArraySize(g_PS_PassthroughDepth2D), NULL, &mDepthPS);
- ASSERT(SUCCEEDED(result));
- d3d11::SetDebugName(mDepthPS, "Blit11 2D depth pixel shader");
-
- D3D11_INPUT_ELEMENT_DESC quad3DLayout[] =
- {
- { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
- { "LAYER", 0, DXGI_FORMAT_R32_UINT, 0, 8, D3D11_INPUT_PER_VERTEX_DATA, 0 },
- { "TEXCOORD", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
- };
-
- result = device->CreateInputLayout(quad3DLayout, ArraySize(quad3DLayout), g_VS_Passthrough3D, ArraySize(g_VS_Passthrough3D), &mQuad3DIL);
- ASSERT(SUCCEEDED(result));
- d3d11::SetDebugName(mQuad3DIL, "Blit11 3D input layout");
-
- result = device->CreateVertexShader(g_VS_Passthrough3D, ArraySize(g_VS_Passthrough3D), NULL, &mQuad3DVS);
- ASSERT(SUCCEEDED(result));
- d3d11::SetDebugName(mQuad3DVS, "Blit11 3D vertex shader");
-
- result = device->CreateGeometryShader(g_GS_Passthrough3D, ArraySize(g_GS_Passthrough3D), NULL, &mQuad3DGS);
- ASSERT(SUCCEEDED(result));
- d3d11::SetDebugName(mQuad3DGS, "Renderer11 copy 3D texture geometry shader");
+ freeResources();
+ return gl::Error(GL_OUT_OF_MEMORY,
+ "Failed to create blit depth stencil state, HRESULT: 0x%X", result);
}
-
- buildShaderMap();
+ d3d11::SetDebugName(mDepthStencilState, "Blit11 depth stencil state");
D3D11_BUFFER_DESC swizzleBufferDesc;
swizzleBufferDesc.ByteWidth = sizeof(unsigned int) * 4;
@@ -328,12 +426,22 @@ Blit11::Blit11(Renderer11 *renderer)
swizzleBufferDesc.MiscFlags = 0;
swizzleBufferDesc.StructureByteStride = 0;
- result = device->CreateBuffer(&swizzleBufferDesc, NULL, &mSwizzleCB);
+ result = device->CreateBuffer(&swizzleBufferDesc, nullptr, &mSwizzleCB);
ASSERT(SUCCEEDED(result));
+ if (FAILED(result))
+ {
+ freeResources();
+ return gl::Error(GL_OUT_OF_MEMORY, "Failed to create blit swizzle buffer, HRESULT: 0x%X",
+ result);
+ }
d3d11::SetDebugName(mSwizzleCB, "Blit11 swizzle constant buffer");
+
+ mResourcesInitialized = true;
+
+ return gl::Error(GL_NO_ERROR);
}
-Blit11::~Blit11()
+void Blit11::freeResources()
{
SafeRelease(mVertexBuffer);
SafeRelease(mPointSampler);
@@ -341,41 +449,176 @@ Blit11::~Blit11()
SafeRelease(mScissorEnabledRasterizerState);
SafeRelease(mScissorDisabledRasterizerState);
SafeRelease(mDepthStencilState);
+ SafeRelease(mSwizzleCB);
- SafeRelease(mQuad2DIL);
- SafeRelease(mQuad2DVS);
- SafeRelease(mDepthPS);
-
- SafeRelease(mQuad3DIL);
- SafeRelease(mQuad3DVS);
- SafeRelease(mQuad3DGS);
+ mResourcesInitialized = false;
+}
- SafeRelease(mSwizzleCB);
+// static
+Blit11::BlitShaderType Blit11::GetBlitShaderType(GLenum destinationFormat, bool isSigned, ShaderDimension dimension)
+{
+ if (dimension == SHADER_3D)
+ {
+ if (isSigned)
+ {
+ switch (destinationFormat)
+ {
+ case GL_RGBA_INTEGER: return BLITSHADER_3D_RGBAI;
+ case GL_RGB_INTEGER: return BLITSHADER_3D_RGBI;
+ case GL_RG_INTEGER: return BLITSHADER_3D_RGI;
+ case GL_RED_INTEGER: return BLITSHADER_3D_RI;
+ default:
+ UNREACHABLE();
+ return BLITSHADER_INVALID;
+ }
+ }
+ else
+ {
+ switch (destinationFormat)
+ {
+ case GL_RGBA: return BLITSHADER_3D_RGBAF;
+ case GL_RGBA_INTEGER: return BLITSHADER_3D_RGBAUI;
+ case GL_BGRA_EXT: return BLITSHADER_3D_BGRAF;
+ case GL_RGB: return BLITSHADER_3D_RGBF;
+ case GL_RGB_INTEGER: return BLITSHADER_3D_RGBUI;
+ case GL_RG: return BLITSHADER_3D_RGF;
+ case GL_RG_INTEGER: return BLITSHADER_3D_RGUI;
+ case GL_RED: return BLITSHADER_3D_RF;
+ case GL_RED_INTEGER: return BLITSHADER_3D_RUI;
+ case GL_ALPHA: return BLITSHADER_3D_ALPHA;
+ case GL_LUMINANCE: return BLITSHADER_3D_LUMA;
+ case GL_LUMINANCE_ALPHA: return BLITSHADER_3D_LUMAALPHA;
+ default:
+ UNREACHABLE();
+ return BLITSHADER_INVALID;
+ }
+ }
+ }
+ else if (isSigned)
+ {
+ switch (destinationFormat)
+ {
+ case GL_RGBA_INTEGER: return BLITSHADER_2D_RGBAI;
+ case GL_RGB_INTEGER: return BLITSHADER_2D_RGBI;
+ case GL_RG_INTEGER: return BLITSHADER_2D_RGI;
+ case GL_RED_INTEGER: return BLITSHADER_2D_RI;
+ default:
+ UNREACHABLE();
+ return BLITSHADER_INVALID;
+ }
+ }
+ else
+ {
+ switch (destinationFormat)
+ {
+ case GL_RGBA: return BLITSHADER_2D_RGBAF;
+ case GL_RGBA_INTEGER: return BLITSHADER_2D_RGBAUI;
+ case GL_BGRA_EXT: return BLITSHADER_2D_BGRAF;
+ case GL_RGB: return BLITSHADER_2D_RGBF;
+ case GL_RGB_INTEGER: return BLITSHADER_2D_RGBUI;
+ case GL_RG: return BLITSHADER_2D_RGF;
+ case GL_RG_INTEGER: return BLITSHADER_2D_RGUI;
+ case GL_RED: return BLITSHADER_2D_RF;
+ case GL_RED_INTEGER: return BLITSHADER_2D_RUI;
+ case GL_ALPHA: return BLITSHADER_2D_ALPHA;
+ case GL_LUMINANCE: return BLITSHADER_2D_LUMA;
+ case GL_LUMINANCE_ALPHA: return BLITSHADER_2D_LUMAALPHA;
+ default:
+ UNREACHABLE();
+ return BLITSHADER_INVALID;
+ }
+ }
+}
- clearShaderMap();
+// static
+Blit11::SwizzleShaderType Blit11::GetSwizzleShaderType(GLenum type, D3D11_SRV_DIMENSION dimensionality)
+{
+ switch (dimensionality)
+ {
+ case D3D11_SRV_DIMENSION_TEXTURE2D:
+ switch (type)
+ {
+ case GL_FLOAT: return SWIZZLESHADER_2D_FLOAT;
+ case GL_UNSIGNED_INT: return SWIZZLESHADER_2D_UINT;
+ case GL_INT: return SWIZZLESHADER_2D_INT;
+ default:
+ UNREACHABLE();
+ return SWIZZLESHADER_INVALID;
+ }
+ case D3D11_SRV_DIMENSION_TEXTURECUBE:
+ switch (type)
+ {
+ case GL_FLOAT: return SWIZZLESHADER_CUBE_FLOAT;
+ case GL_UNSIGNED_INT: return SWIZZLESHADER_CUBE_UINT;
+ case GL_INT: return SWIZZLESHADER_CUBE_INT;
+ default:
+ UNREACHABLE();
+ return SWIZZLESHADER_INVALID;
+ }
+ case D3D11_SRV_DIMENSION_TEXTURE3D:
+ switch (type)
+ {
+ case GL_FLOAT: return SWIZZLESHADER_3D_FLOAT;
+ case GL_UNSIGNED_INT: return SWIZZLESHADER_3D_UINT;
+ case GL_INT: return SWIZZLESHADER_3D_INT;
+ default:
+ UNREACHABLE();
+ return SWIZZLESHADER_INVALID;
+ }
+ case D3D11_SRV_DIMENSION_TEXTURE2DARRAY:
+ switch (type)
+ {
+ case GL_FLOAT: return SWIZZLESHADER_ARRAY_FLOAT;
+ case GL_UNSIGNED_INT: return SWIZZLESHADER_ARRAY_UINT;
+ case GL_INT: return SWIZZLESHADER_ARRAY_INT;
+ default:
+ UNREACHABLE();
+ return SWIZZLESHADER_INVALID;
+ }
+ default:
+ UNREACHABLE();
+ return SWIZZLESHADER_INVALID;
+ }
}
-static inline unsigned int GetSwizzleIndex(GLenum swizzle)
+Blit11::ShaderSupport Blit11::getShaderSupport(const Shader &shader)
{
- unsigned int colorIndex = 0;
+ ID3D11Device *device = mRenderer->getDevice();
+ ShaderSupport support;
- switch (swizzle)
+ if (shader.dimension == SHADER_2D)
{
- case GL_RED: colorIndex = 0; break;
- case GL_GREEN: colorIndex = 1; break;
- case GL_BLUE: colorIndex = 2; break;
- case GL_ALPHA: colorIndex = 3; break;
- case GL_ZERO: colorIndex = 4; break;
- case GL_ONE: colorIndex = 5; break;
- default: UNREACHABLE(); break;
+ support.inputLayout = mQuad2DIL.resolve(device);
+ support.vertexShader = mQuad2DVS.resolve(device);
+ support.geometryShader = nullptr;
+ support.vertexWriteFunction = Write2DVertices;
+ }
+ else
+ {
+ ASSERT(shader.dimension == SHADER_3D);
+ support.inputLayout = mQuad3DIL.resolve(device);
+ support.vertexShader = mQuad3DVS.resolve(device);
+ support.geometryShader = mQuad3DGS.resolve(device);
+ support.vertexWriteFunction = Write3DVertices;
}
- return colorIndex;
+ return support;
}
-gl::Error Blit11::swizzleTexture(ID3D11ShaderResourceView *source, ID3D11RenderTargetView *dest, const gl::Extents &size,
- GLenum swizzleRed, GLenum swizzleGreen, GLenum swizzleBlue, GLenum swizzleAlpha)
+gl::Error Blit11::swizzleTexture(ID3D11ShaderResourceView *source,
+ ID3D11RenderTargetView *dest,
+ const gl::Extents &size,
+ GLenum swizzleRed,
+ GLenum swizzleGreen,
+ GLenum swizzleBlue,
+ GLenum swizzleAlpha)
{
+ gl::Error error = initResources();
+ if (error.isError())
+ {
+ return error;
+ }
+
HRESULT result;
ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
@@ -404,19 +647,13 @@ gl::Error Blit11::swizzleTexture(ID3D11ShaderResourceView *source, ID3D11RenderT
break;
}
- SwizzleParameters parameters = { 0 };
- parameters.mDestinationType = shaderType;
- parameters.mViewDimension = sourceSRVDesc.ViewDimension;
-
- SwizzleShaderMap::const_iterator i = mSwizzleShaderMap.find(parameters);
- if (i == mSwizzleShaderMap.end())
+ const Shader *shader = nullptr;
+ error = getSwizzleShader(shaderType, sourceSRVDesc.ViewDimension, &shader);
+ if (error.isError())
{
- UNREACHABLE();
- return gl::Error(GL_INVALID_OPERATION, "Internal error, missing swizzle shader.");
+ return error;
}
- const Shader &shader = i->second;
-
// Set vertices
D3D11_MAPPED_SUBRESOURCE mappedResource;
result = deviceContext->Map(mVertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
@@ -425,13 +662,15 @@ gl::Error Blit11::swizzleTexture(ID3D11ShaderResourceView *source, ID3D11RenderT
return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal vertex buffer for swizzle, HRESULT: 0x%X.", result);
}
+ const ShaderSupport &support = getShaderSupport(*shader);
+
UINT stride = 0;
UINT startIdx = 0;
UINT drawCount = 0;
D3D11_PRIMITIVE_TOPOLOGY topology;
gl::Box area(0, 0, 0, size.width, size.height, size.depth);
- shader.mVertexWriteFunction(area, size, area, size, mappedResource.pData, &stride, &drawCount, &topology);
+ support.vertexWriteFunction(area, size, area, size, mappedResource.pData, &stride, &drawCount, &topology);
deviceContext->Unmap(mVertexBuffer, 0);
@@ -457,20 +696,21 @@ gl::Error Blit11::swizzleTexture(ID3D11ShaderResourceView *source, ID3D11RenderT
deviceContext->PSSetConstantBuffers(0, 1, &mSwizzleCB);
// Apply state
- deviceContext->OMSetBlendState(NULL, NULL, 0xFFFFFFF);
- deviceContext->OMSetDepthStencilState(NULL, 0xFFFFFFFF);
+ deviceContext->OMSetBlendState(nullptr, nullptr, 0xFFFFFFF);
+ deviceContext->OMSetDepthStencilState(nullptr, 0xFFFFFFFF);
deviceContext->RSSetState(mScissorDisabledRasterizerState);
// Apply shaders
- deviceContext->IASetInputLayout(shader.mInputLayout);
+ deviceContext->IASetInputLayout(support.inputLayout);
deviceContext->IASetPrimitiveTopology(topology);
- deviceContext->VSSetShader(shader.mVertexShader, NULL, 0);
+ deviceContext->VSSetShader(support.vertexShader, nullptr, 0);
- deviceContext->PSSetShader(shader.mPixelShader, NULL, 0);
- deviceContext->GSSetShader(shader.mGeometryShader, NULL, 0);
+ deviceContext->PSSetShader(shader->pixelShader, nullptr, 0);
+ deviceContext->GSSetShader(support.geometryShader, nullptr, 0);
// Unset the currently bound shader resource to avoid conflicts
- mRenderer->setShaderResource(gl::SAMPLER_PIXEL, 0, NULL);
+ auto stateManager = mRenderer->getStateManager();
+ stateManager->setShaderResource(gl::SAMPLER_PIXEL, 0, nullptr);
// Apply render target
mRenderer->setOneTimeRenderTarget(dest);
@@ -479,14 +719,14 @@ gl::Error Blit11::swizzleTexture(ID3D11ShaderResourceView *source, ID3D11RenderT
D3D11_VIEWPORT viewport;
viewport.TopLeftX = 0;
viewport.TopLeftY = 0;
- viewport.Width = size.width;
- viewport.Height = size.height;
+ viewport.Width = static_cast<FLOAT>(size.width);
+ viewport.Height = static_cast<FLOAT>(size.height);
viewport.MinDepth = 0.0f;
viewport.MaxDepth = 1.0f;
deviceContext->RSSetViewports(1, &viewport);
// Apply textures
- mRenderer->setShaderResource(gl::SAMPLER_PIXEL, 0, source);
+ stateManager->setShaderResource(gl::SAMPLER_PIXEL, 0, source);
// Apply samplers
deviceContext->PSSetSamplers(0, 1, &mPointSampler);
@@ -495,12 +735,12 @@ gl::Error Blit11::swizzleTexture(ID3D11ShaderResourceView *source, ID3D11RenderT
deviceContext->Draw(drawCount, 0);
// Unbind textures and render targets and vertex buffer
- mRenderer->setShaderResource(gl::SAMPLER_PIXEL, 0, NULL);
+ stateManager->setShaderResource(gl::SAMPLER_PIXEL, 0, nullptr);
mRenderer->unapplyRenderTargets();
UINT zero = 0;
- ID3D11Buffer *const nullBuffer = NULL;
+ ID3D11Buffer *const nullBuffer = nullptr;
deviceContext->IASetVertexBuffers(0, 1, &nullBuffer, &zero, &zero);
mRenderer->markAllStateDirty();
@@ -508,10 +748,23 @@ gl::Error Blit11::swizzleTexture(ID3D11ShaderResourceView *source, ID3D11RenderT
return gl::Error(GL_NO_ERROR);
}
-gl::Error Blit11::copyTexture(ID3D11ShaderResourceView *source, const gl::Box &sourceArea, const gl::Extents &sourceSize,
- ID3D11RenderTargetView *dest, const gl::Box &destArea, const gl::Extents &destSize,
- const gl::Rectangle *scissor, GLenum destFormat, GLenum filter)
+gl::Error Blit11::copyTexture(ID3D11ShaderResourceView *source,
+ const gl::Box &sourceArea,
+ const gl::Extents &sourceSize,
+ ID3D11RenderTargetView *dest,
+ const gl::Box &destArea,
+ const gl::Extents &destSize,
+ const gl::Rectangle *scissor,
+ GLenum destFormat,
+ GLenum filter,
+ bool maskOffAlpha)
{
+ gl::Error error = initResources();
+ if (error.isError())
+ {
+ return error;
+ }
+
HRESULT result;
ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
@@ -523,19 +776,17 @@ gl::Error Blit11::copyTexture(ID3D11ShaderResourceView *source, const gl::Box &s
const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(sourceSRVDesc.Format);
const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(dxgiFormatInfo.internalFormat);
- BlitParameters parameters = { 0 };
- parameters.mDestinationFormat = destFormat;
- parameters.mSignedInteger = (internalFormatInfo.componentType == GL_INT);
- parameters.m3DBlit = sourceSRVDesc.ViewDimension == D3D11_SRV_DIMENSION_TEXTURE3D;
+ bool isSigned = (internalFormatInfo.componentType == GL_INT);
+ ShaderDimension dimension = (sourceSRVDesc.ViewDimension == D3D11_SRV_DIMENSION_TEXTURE3D) ? SHADER_3D : SHADER_2D;
- BlitShaderMap::const_iterator i = mBlitShaderMap.find(parameters);
- if (i == mBlitShaderMap.end())
+ const Shader *shader = nullptr;
+ error = getBlitShader(destFormat, isSigned, dimension, &shader);
+ if (error.isError())
{
- UNREACHABLE();
- return gl::Error(GL_OUT_OF_MEMORY, "Could not find appropriate shader for internal texture blit.");
+ return error;
}
- const Shader& shader = i->second;
+ const ShaderSupport &support = getShaderSupport(*shader);
// Set vertices
D3D11_MAPPED_SUBRESOURCE mappedResource;
@@ -550,7 +801,7 @@ gl::Error Blit11::copyTexture(ID3D11ShaderResourceView *source, const gl::Box &s
UINT drawCount = 0;
D3D11_PRIMITIVE_TOPOLOGY topology;
- shader.mVertexWriteFunction(sourceArea, sourceSize, destArea, destSize, mappedResource.pData,
+ support.vertexWriteFunction(sourceArea, sourceSize, destArea, destSize, mappedResource.pData,
&stride, &drawCount, &topology);
deviceContext->Unmap(mVertexBuffer, 0);
@@ -559,8 +810,17 @@ gl::Error Blit11::copyTexture(ID3D11ShaderResourceView *source, const gl::Box &s
deviceContext->IASetVertexBuffers(0, 1, &mVertexBuffer, &stride, &startIdx);
// Apply state
- deviceContext->OMSetBlendState(NULL, NULL, 0xFFFFFFF);
- deviceContext->OMSetDepthStencilState(NULL, 0xFFFFFFFF);
+ if (maskOffAlpha)
+ {
+ ID3D11BlendState *blendState = mAlphaMaskBlendState.resolve(mRenderer->getDevice());
+ ASSERT(blendState);
+ deviceContext->OMSetBlendState(blendState, nullptr, 0xFFFFFFF);
+ }
+ else
+ {
+ deviceContext->OMSetBlendState(nullptr, nullptr, 0xFFFFFFF);
+ }
+ deviceContext->OMSetDepthStencilState(nullptr, 0xFFFFFFFF);
if (scissor)
{
@@ -579,15 +839,16 @@ gl::Error Blit11::copyTexture(ID3D11ShaderResourceView *source, const gl::Box &s
}
// Apply shaders
- deviceContext->IASetInputLayout(shader.mInputLayout);
+ deviceContext->IASetInputLayout(support.inputLayout);
deviceContext->IASetPrimitiveTopology(topology);
- deviceContext->VSSetShader(shader.mVertexShader, NULL, 0);
+ deviceContext->VSSetShader(support.vertexShader, nullptr, 0);
- deviceContext->PSSetShader(shader.mPixelShader, NULL, 0);
- deviceContext->GSSetShader(shader.mGeometryShader, NULL, 0);
+ deviceContext->PSSetShader(shader->pixelShader, nullptr, 0);
+ deviceContext->GSSetShader(support.geometryShader, nullptr, 0);
// Unset the currently bound shader resource to avoid conflicts
- mRenderer->setShaderResource(gl::SAMPLER_PIXEL, 0, NULL);
+ auto stateManager = mRenderer->getStateManager();
+ stateManager->setShaderResource(gl::SAMPLER_PIXEL, 0, nullptr);
// Apply render target
mRenderer->setOneTimeRenderTarget(dest);
@@ -596,17 +857,17 @@ gl::Error Blit11::copyTexture(ID3D11ShaderResourceView *source, const gl::Box &s
D3D11_VIEWPORT viewport;
viewport.TopLeftX = 0;
viewport.TopLeftY = 0;
- viewport.Width = destSize.width;
- viewport.Height = destSize.height;
+ viewport.Width = static_cast<FLOAT>(destSize.width);
+ viewport.Height = static_cast<FLOAT>(destSize.height);
viewport.MinDepth = 0.0f;
viewport.MaxDepth = 1.0f;
deviceContext->RSSetViewports(1, &viewport);
// Apply textures
- mRenderer->setShaderResource(gl::SAMPLER_PIXEL, 0, source);
+ stateManager->setShaderResource(gl::SAMPLER_PIXEL, 0, source);
// Apply samplers
- ID3D11SamplerState *sampler = NULL;
+ ID3D11SamplerState *sampler = nullptr;
switch (filter)
{
case GL_NEAREST: sampler = mPointSampler; break;
@@ -622,12 +883,12 @@ gl::Error Blit11::copyTexture(ID3D11ShaderResourceView *source, const gl::Box &s
deviceContext->Draw(drawCount, 0);
// Unbind textures and render targets and vertex buffer
- mRenderer->setShaderResource(gl::SAMPLER_PIXEL, 0, NULL);
+ stateManager->setShaderResource(gl::SAMPLER_PIXEL, 0, nullptr);
mRenderer->unapplyRenderTargets();
UINT zero = 0;
- ID3D11Buffer *const nullBuffer = NULL;
+ ID3D11Buffer *const nullBuffer = nullptr;
deviceContext->IASetVertexBuffers(0, 1, &nullBuffer, &zero, &zero);
mRenderer->markAllStateDirty();
@@ -648,6 +909,12 @@ gl::Error Blit11::copyDepth(ID3D11ShaderResourceView *source, const gl::Box &sou
ID3D11DepthStencilView *dest, const gl::Box &destArea, const gl::Extents &destSize,
const gl::Rectangle *scissor)
{
+ gl::Error error = initResources();
+ if (error.isError())
+ {
+ return error;
+ }
+
HRESULT result;
ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
@@ -673,7 +940,7 @@ gl::Error Blit11::copyDepth(ID3D11ShaderResourceView *source, const gl::Box &sou
deviceContext->IASetVertexBuffers(0, 1, &mVertexBuffer, &stride, &startIdx);
// Apply state
- deviceContext->OMSetBlendState(NULL, NULL, 0xFFFFFFF);
+ deviceContext->OMSetBlendState(nullptr, nullptr, 0xFFFFFFF);
deviceContext->OMSetDepthStencilState(mDepthStencilState, 0xFFFFFFFF);
if (scissor)
@@ -692,32 +959,40 @@ gl::Error Blit11::copyDepth(ID3D11ShaderResourceView *source, const gl::Box &sou
deviceContext->RSSetState(mScissorDisabledRasterizerState);
}
+ ID3D11Device *device = mRenderer->getDevice();
+ ID3D11VertexShader *quad2DVS = mQuad2DVS.resolve(device);
+ if (quad2DVS == nullptr)
+ {
+ return gl::Error(GL_INVALID_OPERATION, "Error compiling internal 2D blit vertex shader");
+ }
+
// Apply shaders
- deviceContext->IASetInputLayout(mQuad2DIL);
+ deviceContext->IASetInputLayout(mQuad2DIL.resolve(device));
deviceContext->IASetPrimitiveTopology(topology);
- deviceContext->VSSetShader(mQuad2DVS, NULL, 0);
+ deviceContext->VSSetShader(quad2DVS, nullptr, 0);
- deviceContext->PSSetShader(mDepthPS, NULL, 0);
- deviceContext->GSSetShader(NULL, NULL, 0);
+ deviceContext->PSSetShader(mDepthPS.resolve(device), nullptr, 0);
+ deviceContext->GSSetShader(nullptr, nullptr, 0);
// Unset the currently bound shader resource to avoid conflicts
- mRenderer->setShaderResource(gl::SAMPLER_PIXEL, 0, NULL);
+ auto stateManager = mRenderer->getStateManager();
+ stateManager->setShaderResource(gl::SAMPLER_PIXEL, 0, nullptr);
// Apply render target
- deviceContext->OMSetRenderTargets(0, NULL, dest);
+ deviceContext->OMSetRenderTargets(0, nullptr, dest);
// Set the viewport
D3D11_VIEWPORT viewport;
viewport.TopLeftX = 0;
viewport.TopLeftY = 0;
- viewport.Width = destSize.width;
- viewport.Height = destSize.height;
+ viewport.Width = static_cast<FLOAT>(destSize.width);
+ viewport.Height = static_cast<FLOAT>(destSize.height);
viewport.MinDepth = 0.0f;
viewport.MaxDepth = 1.0f;
deviceContext->RSSetViewports(1, &viewport);
// Apply textures
- mRenderer->setShaderResource(gl::SAMPLER_PIXEL, 0, source);
+ stateManager->setShaderResource(gl::SAMPLER_PIXEL, 0, source);
// Apply samplers
deviceContext->PSSetSamplers(0, 1, &mPointSampler);
@@ -726,12 +1001,12 @@ gl::Error Blit11::copyDepth(ID3D11ShaderResourceView *source, const gl::Box &sou
deviceContext->Draw(drawCount, 0);
// Unbind textures and render targets and vertex buffer
- mRenderer->setShaderResource(gl::SAMPLER_PIXEL, 0, NULL);
+ stateManager->setShaderResource(gl::SAMPLER_PIXEL, 0, nullptr);
mRenderer->unapplyRenderTargets();
UINT zero = 0;
- ID3D11Buffer *const nullBuffer = NULL;
+ ID3D11Buffer *const nullBuffer = nullptr;
deviceContext->IASetVertexBuffers(0, 1, &nullBuffer, &zero, &zero);
mRenderer->markAllStateDirty();
@@ -752,6 +1027,12 @@ gl::Error Blit11::copyDepthStencil(ID3D11Resource *source, unsigned int sourceSu
ID3D11Resource *dest, unsigned int destSubresource, const gl::Box &destArea, const gl::Extents &destSize,
const gl::Rectangle *scissor, bool stencilOnly)
{
+ gl::Error error = initResources();
+ if (error.isError())
+ {
+ return error;
+ }
+
ID3D11Device *device = mRenderer->getDevice();
ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
@@ -826,7 +1107,7 @@ gl::Error Blit11::copyDepthStencil(ID3D11Resource *source, unsigned int sourceSu
float yPerc = static_cast<float>(y - destArea.y) / (destArea.height - 1);
// Interpolate using the original source rectangle to determine which row to sample from while clamping to the edges
- unsigned int readRow = gl::clamp(sourceArea.y + floor(yPerc * (sourceArea.height - 1) + 0.5f), 0, sourceSize.height - 1);
+ unsigned int readRow = static_cast<unsigned int>(gl::clamp(sourceArea.y + floor(yPerc * (sourceArea.height - 1) + 0.5f), 0, sourceSize.height - 1));
unsigned int writeRow = y;
if (wholeRowCopy)
@@ -848,7 +1129,7 @@ gl::Error Blit11::copyDepthStencil(ID3D11Resource *source, unsigned int sourceSu
float xPerc = static_cast<float>(x - destArea.x) / (destArea.width - 1);
// Interpolate the original source rectangle to determine which column to sample from while clamping to the edges
- unsigned int readColumn = gl::clamp(sourceArea.x + floor(xPerc * (sourceArea.width - 1) + 0.5f), 0, sourceSize.width - 1);
+ unsigned int readColumn = static_cast<unsigned int>(gl::clamp(sourceArea.x + floor(xPerc * (sourceArea.width - 1) + 0.5f), 0, sourceSize.width - 1));
unsigned int writeColumn = x;
void *sourcePixel = reinterpret_cast<char*>(sourceMapping.pData) +
@@ -868,14 +1149,14 @@ gl::Error Blit11::copyDepthStencil(ID3D11Resource *source, unsigned int sourceSu
// HACK: Use ID3D11DevicContext::UpdateSubresource which causes an extra copy compared to ID3D11DevicContext::CopySubresourceRegion
// according to MSDN.
- deviceContext->UpdateSubresource(dest, destSubresource, NULL, destMapping.pData, destMapping.RowPitch, destMapping.DepthPitch);
+ deviceContext->UpdateSubresource(dest, destSubresource, nullptr, destMapping.pData, destMapping.RowPitch, destMapping.DepthPitch);
deviceContext->Unmap(sourceStaging, 0);
deviceContext->Unmap(destStaging, 0);
// TODO: Determine why this call to ID3D11DevicContext::CopySubresourceRegion causes a TDR timeout on some
// systems when called repeatedly.
- // deviceContext->CopySubresourceRegion(dest, destSubresource, 0, 0, 0, destStaging, 0, NULL);
+ // deviceContext->CopySubresourceRegion(dest, destSubresource, 0, 0, 0, destStaging, 0, nullptr);
SafeRelease(sourceStaging);
SafeRelease(destStaging);
@@ -883,177 +1164,242 @@ gl::Error Blit11::copyDepthStencil(ID3D11Resource *source, unsigned int sourceSu
return gl::Error(GL_NO_ERROR);
}
-bool Blit11::compareBlitParameters(const Blit11::BlitParameters &a, const Blit11::BlitParameters &b)
+void Blit11::addBlitShaderToMap(BlitShaderType blitShaderType, ShaderDimension dimension, ID3D11PixelShader *ps)
{
- return memcmp(&a, &b, sizeof(Blit11::BlitParameters)) < 0;
-}
+ ASSERT(mBlitShaderMap.find(blitShaderType) == mBlitShaderMap.end());
+ ASSERT(ps);
-bool Blit11::compareSwizzleParameters(const SwizzleParameters &a, const SwizzleParameters &b)
-{
- return memcmp(&a, &b, sizeof(Blit11::SwizzleParameters)) < 0;
+ Shader shader;
+ shader.dimension = dimension;
+ shader.pixelShader = ps;
+
+ mBlitShaderMap[blitShaderType] = shader;
}
-void Blit11::add2DBlitShaderToMap(GLenum destFormat, bool signedInteger, ID3D11PixelShader *ps)
+void Blit11::addSwizzleShaderToMap(SwizzleShaderType swizzleShaderType, ShaderDimension dimension, ID3D11PixelShader *ps)
{
- BlitParameters params = { 0 };
- params.mDestinationFormat = destFormat;
- params.mSignedInteger = signedInteger;
- params.m3DBlit = false;
-
- ASSERT(mBlitShaderMap.find(params) == mBlitShaderMap.end());
+ ASSERT(mSwizzleShaderMap.find(swizzleShaderType) == mSwizzleShaderMap.end());
ASSERT(ps);
Shader shader;
- shader.mVertexWriteFunction = Write2DVertices;
- shader.mInputLayout = mQuad2DIL;
- shader.mVertexShader = mQuad2DVS;
- shader.mGeometryShader = NULL;
- shader.mPixelShader = ps;
+ shader.dimension = dimension;
+ shader.pixelShader = ps;
- mBlitShaderMap[params] = shader;
+ mSwizzleShaderMap[swizzleShaderType] = shader;
}
-void Blit11::add3DBlitShaderToMap(GLenum destFormat, bool signedInteger, ID3D11PixelShader *ps)
+void Blit11::clearShaderMap()
{
- BlitParameters params = { 0 };
- params.mDestinationFormat = destFormat;
- params.mSignedInteger = signedInteger;
- params.m3DBlit = true;
-
- ASSERT(mBlitShaderMap.find(params) == mBlitShaderMap.end());
- ASSERT(ps);
-
- Shader shader;
- shader.mVertexWriteFunction = Write3DVertices;
- shader.mInputLayout = mQuad3DIL;
- shader.mVertexShader = mQuad3DVS;
- shader.mGeometryShader = mQuad3DGS;
- shader.mPixelShader = ps;
+ for (auto &blitShader : mBlitShaderMap)
+ {
+ SafeRelease(blitShader.second.pixelShader);
+ }
+ mBlitShaderMap.clear();
- mBlitShaderMap[params] = shader;
+ for (auto &swizzleShader : mSwizzleShaderMap)
+ {
+ SafeRelease(swizzleShader.second.pixelShader);
+ }
+ mSwizzleShaderMap.clear();
}
-void Blit11::addSwizzleShaderToMap(GLenum destType, D3D11_SRV_DIMENSION viewDimension, ID3D11PixelShader *ps)
+gl::Error Blit11::getBlitShader(GLenum destFormat, bool isSigned, ShaderDimension dimension, const Shader **shader)
{
- SwizzleParameters params = { 0 };
- params.mDestinationType = destType;
- params.mViewDimension = viewDimension;
+ BlitShaderType blitShaderType = GetBlitShaderType(destFormat, isSigned, dimension);
- ASSERT(mSwizzleShaderMap.find(params) == mSwizzleShaderMap.end());
- ASSERT(ps);
+ if (blitShaderType == BLITSHADER_INVALID)
+ {
+ return gl::Error(GL_INVALID_OPERATION, "Internal blit shader type mismatch");
+ }
- Shader shader;
- switch (viewDimension)
+ auto blitShaderIt = mBlitShaderMap.find(blitShaderType);
+ if (blitShaderIt != mBlitShaderMap.end())
{
- case D3D_SRV_DIMENSION_TEXTURE2D:
- shader.mVertexWriteFunction = Write2DVertices;
- shader.mInputLayout = mQuad2DIL;
- shader.mVertexShader = mQuad2DVS;
- shader.mGeometryShader = NULL;
- break;
+ *shader = &blitShaderIt->second;
+ return gl::Error(GL_NO_ERROR);
+ }
- case D3D_SRV_DIMENSION_TEXTURE3D:
- case D3D_SRV_DIMENSION_TEXTURE2DARRAY:
- case D3D_SRV_DIMENSION_TEXTURECUBE:
- shader.mVertexWriteFunction = Write3DVertices;
- shader.mInputLayout = mQuad3DIL;
- shader.mVertexShader = mQuad3DVS;
- shader.mGeometryShader = mQuad3DGS;
- break;
+ ASSERT(dimension == SHADER_2D || mRenderer->isES3Capable());
+ ID3D11Device *device = mRenderer->getDevice();
+
+ switch (blitShaderType)
+ {
+ case BLITSHADER_2D_RGBAF:
+ addBlitShaderToMap(blitShaderType, SHADER_2D, d3d11::CompilePS(device, g_PS_PassthroughRGBA2D, "Blit11 2D RGBA pixel shader"));
+ break;
+ case BLITSHADER_2D_BGRAF:
+ addBlitShaderToMap(blitShaderType, SHADER_2D, d3d11::CompilePS(device, g_PS_PassthroughRGBA2D, "Blit11 2D BGRA pixel shader"));
+ break;
+ case BLITSHADER_2D_RGBF:
+ addBlitShaderToMap(blitShaderType, SHADER_2D, d3d11::CompilePS(device, g_PS_PassthroughRGB2D, "Blit11 2D RGB pixel shader"));
+ break;
+ case BLITSHADER_2D_RGF:
+ addBlitShaderToMap(blitShaderType, SHADER_2D, d3d11::CompilePS(device, g_PS_PassthroughRG2D, "Blit11 2D RG pixel shader"));
+ break;
+ case BLITSHADER_2D_RF:
+ addBlitShaderToMap(blitShaderType, SHADER_2D, d3d11::CompilePS(device, g_PS_PassthroughR2D, "Blit11 2D R pixel shader"));
+ break;
+ case BLITSHADER_2D_ALPHA:
+ addBlitShaderToMap(blitShaderType, SHADER_2D, d3d11::CompilePS(device, g_PS_PassthroughRGBA2D, "Blit11 2D alpha pixel shader"));
+ break;
+ case BLITSHADER_2D_LUMA:
+ addBlitShaderToMap(blitShaderType, SHADER_2D, d3d11::CompilePS(device, g_PS_PassthroughLum2D, "Blit11 2D lum pixel shader"));
+ break;
+ case BLITSHADER_2D_LUMAALPHA:
+ addBlitShaderToMap(blitShaderType, SHADER_2D, d3d11::CompilePS(device, g_PS_PassthroughLumAlpha2D, "Blit11 2D luminance alpha pixel shader"));
+ break;
+ case BLITSHADER_2D_RGBAUI:
+ addBlitShaderToMap(blitShaderType, SHADER_2D, d3d11::CompilePS(device, g_PS_PassthroughRGBA2DUI, "Blit11 2D RGBA UI pixel shader"));
+ break;
+ case BLITSHADER_2D_RGBAI:
+ addBlitShaderToMap(blitShaderType, SHADER_2D, d3d11::CompilePS(device, g_PS_PassthroughRGBA2DI, "Blit11 2D RGBA I pixel shader"));
+ break;
+ case BLITSHADER_2D_RGBUI:
+ addBlitShaderToMap(blitShaderType, SHADER_2D, d3d11::CompilePS(device, g_PS_PassthroughRGB2DUI, "Blit11 2D RGB UI pixel shader"));
+ break;
+ case BLITSHADER_2D_RGBI:
+ addBlitShaderToMap(blitShaderType, SHADER_2D, d3d11::CompilePS(device, g_PS_PassthroughRGB2DI, "Blit11 2D RGB I pixel shader"));
+ break;
+ case BLITSHADER_2D_RGUI:
+ addBlitShaderToMap(blitShaderType, SHADER_2D, d3d11::CompilePS(device, g_PS_PassthroughRG2DUI, "Blit11 2D RG UI pixel shader"));
+ break;
+ case BLITSHADER_2D_RGI:
+ addBlitShaderToMap(blitShaderType, SHADER_2D, d3d11::CompilePS(device, g_PS_PassthroughRG2DI, "Blit11 2D RG I pixel shader"));
+ break;
+ case BLITSHADER_2D_RUI:
+ addBlitShaderToMap(blitShaderType, SHADER_2D, d3d11::CompilePS(device, g_PS_PassthroughR2DUI, "Blit11 2D R UI pixel shader"));
+ break;
+ case BLITSHADER_2D_RI:
+ addBlitShaderToMap(blitShaderType, SHADER_2D, d3d11::CompilePS(device, g_PS_PassthroughR2DI, "Blit11 2D R I pixel shader"));
+ break;
+ case BLITSHADER_3D_RGBAF:
+ addBlitShaderToMap(blitShaderType, SHADER_3D, d3d11::CompilePS(device, g_PS_PassthroughRGBA3D, "Blit11 3D RGBA pixel shader"));
+ break;
+ case BLITSHADER_3D_RGBAUI:
+ addBlitShaderToMap(blitShaderType, SHADER_3D, d3d11::CompilePS(device, g_PS_PassthroughRGBA3DUI, "Blit11 3D UI RGBA pixel shader"));
+ break;
+ case BLITSHADER_3D_RGBAI:
+ addBlitShaderToMap(blitShaderType, SHADER_3D, d3d11::CompilePS(device, g_PS_PassthroughRGBA3DI, "Blit11 3D I RGBA pixel shader"));
+ break;
+ case BLITSHADER_3D_BGRAF:
+ addBlitShaderToMap(blitShaderType, SHADER_3D, d3d11::CompilePS(device, g_PS_PassthroughRGBA3D, "Blit11 3D BGRA pixel shader"));
+ break;
+ case BLITSHADER_3D_RGBF:
+ addBlitShaderToMap(blitShaderType, SHADER_3D, d3d11::CompilePS(device, g_PS_PassthroughRGB3D, "Blit11 3D RGB pixel shader"));
+ break;
+ case BLITSHADER_3D_RGBUI:
+ addBlitShaderToMap(blitShaderType, SHADER_3D, d3d11::CompilePS(device, g_PS_PassthroughRGB3DUI, "Blit11 3D RGB UI pixel shader"));
+ break;
+ case BLITSHADER_3D_RGBI:
+ addBlitShaderToMap(blitShaderType, SHADER_3D, d3d11::CompilePS(device, g_PS_PassthroughRGB3DI, "Blit11 3D RGB I pixel shader"));
+ break;
+ case BLITSHADER_3D_RGF:
+ addBlitShaderToMap(blitShaderType, SHADER_3D, d3d11::CompilePS(device, g_PS_PassthroughRG3D, "Blit11 3D RG pixel shader"));
+ break;
+ case BLITSHADER_3D_RGUI:
+ addBlitShaderToMap(blitShaderType, SHADER_3D, d3d11::CompilePS(device, g_PS_PassthroughRG3DUI, "Blit11 3D RG UI pixel shader"));
+ break;
+ case BLITSHADER_3D_RGI:
+ addBlitShaderToMap(blitShaderType, SHADER_3D, d3d11::CompilePS(device, g_PS_PassthroughRG3DI, "Blit11 3D RG I pixel shader"));
+ break;
+ case BLITSHADER_3D_RF:
+ addBlitShaderToMap(blitShaderType, SHADER_3D, d3d11::CompilePS(device, g_PS_PassthroughR3D, "Blit11 3D R pixel shader"));
+ break;
+ case BLITSHADER_3D_RUI:
+ addBlitShaderToMap(blitShaderType, SHADER_3D, d3d11::CompilePS(device, g_PS_PassthroughR3DUI, "Blit11 3D R UI pixel shader"));
+ break;
+ case BLITSHADER_3D_RI:
+ addBlitShaderToMap(blitShaderType, SHADER_3D, d3d11::CompilePS(device, g_PS_PassthroughR3DI, "Blit11 3D R I pixel shader"));
+ break;
+ case BLITSHADER_3D_ALPHA:
+ addBlitShaderToMap(blitShaderType, SHADER_3D, d3d11::CompilePS(device, g_PS_PassthroughRGBA3D, "Blit11 3D alpha pixel shader"));
+ break;
+ case BLITSHADER_3D_LUMA:
+ addBlitShaderToMap(blitShaderType, SHADER_3D, d3d11::CompilePS(device, g_PS_PassthroughLum3D, "Blit11 3D luminance pixel shader"));
+ break;
+ case BLITSHADER_3D_LUMAALPHA:
+ addBlitShaderToMap(blitShaderType, SHADER_3D, d3d11::CompilePS(device, g_PS_PassthroughLumAlpha3D, "Blit11 3D luminance alpha pixel shader"));
+ break;
default:
UNREACHABLE();
- break;
+ return gl::Error(GL_INVALID_OPERATION, "Internal error");
}
- shader.mPixelShader = ps;
- mSwizzleShaderMap[params] = shader;
+ blitShaderIt = mBlitShaderMap.find(blitShaderType);
+ ASSERT(blitShaderIt != mBlitShaderMap.end());
+ *shader = &blitShaderIt->second;
+ return gl::Error(GL_NO_ERROR);
}
-void Blit11::buildShaderMap()
+gl::Error Blit11::getSwizzleShader(GLenum type, D3D11_SRV_DIMENSION viewDimension, const Shader **shader)
{
- ID3D11Device *device = mRenderer->getDevice();
+ SwizzleShaderType swizzleShaderType = GetSwizzleShaderType(type, viewDimension);
- // 2D shaders (OpenGL ES 2+)
- add2DBlitShaderToMap(GL_RGBA, false, d3d11::CompilePS(device, g_PS_PassthroughRGBA2D, "Blit11 2D RGBA pixel shader" ));
- add2DBlitShaderToMap(GL_BGRA_EXT, false, d3d11::CompilePS(device, g_PS_PassthroughRGBA2D, "Blit11 2D BGRA pixel shader" ));
- add2DBlitShaderToMap(GL_RGB, false, d3d11::CompilePS(device, g_PS_PassthroughRGB2D, "Blit11 2D RGB pixel shader" ));
- add2DBlitShaderToMap(GL_RG, false, d3d11::CompilePS(device, g_PS_PassthroughRG2D, "Blit11 2D RG pixel shader" ));
- add2DBlitShaderToMap(GL_RED, false, d3d11::CompilePS(device, g_PS_PassthroughR2D, "Blit11 2D R pixel shader" ));
- add2DBlitShaderToMap(GL_ALPHA, false, d3d11::CompilePS(device, g_PS_PassthroughRGBA2D, "Blit11 2D alpha pixel shader" ));
- add2DBlitShaderToMap(GL_LUMINANCE, false, d3d11::CompilePS(device, g_PS_PassthroughLum2D, "Blit11 2D lum pixel shader" ));
- add2DBlitShaderToMap(GL_LUMINANCE_ALPHA, false, d3d11::CompilePS(device, g_PS_PassthroughLumAlpha2D, "Blit11 2D luminance alpha pixel shader"));
-
- // 2D shaders (OpenGL ES 3+)
- if (mRenderer->isES3Capable())
+ if (swizzleShaderType == SWIZZLESHADER_INVALID)
{
- add2DBlitShaderToMap(GL_RGBA_INTEGER, false, d3d11::CompilePS(device, g_PS_PassthroughRGBA2DUI, "Blit11 2D RGBA UI pixel shader" ));
- add2DBlitShaderToMap(GL_RGBA_INTEGER, true, d3d11::CompilePS(device, g_PS_PassthroughRGBA2DI, "Blit11 2D RGBA I pixel shader" ));
- add2DBlitShaderToMap(GL_RGB_INTEGER, false, d3d11::CompilePS(device, g_PS_PassthroughRGB2DUI, "Blit11 2D RGB UI pixel shader" ));
- add2DBlitShaderToMap(GL_RGB_INTEGER, true, d3d11::CompilePS(device, g_PS_PassthroughRGB2DI, "Blit11 2D RGB I pixel shader" ));
- add2DBlitShaderToMap(GL_RG_INTEGER, false, d3d11::CompilePS(device, g_PS_PassthroughRG2DUI, "Blit11 2D RG UI pixel shader" ));
- add2DBlitShaderToMap(GL_RG_INTEGER, true, d3d11::CompilePS(device, g_PS_PassthroughRG2DI, "Blit11 2D RG I pixel shader" ));
- add2DBlitShaderToMap(GL_RED_INTEGER, false, d3d11::CompilePS(device, g_PS_PassthroughR2DUI, "Blit11 2D R UI pixel shader" ));
- add2DBlitShaderToMap(GL_RED_INTEGER, true, d3d11::CompilePS(device, g_PS_PassthroughR2DI, "Blit11 2D R I pixel shader" ));
+ return gl::Error(GL_INVALID_OPERATION, "Swizzle shader type not found");
}
- // 3D shaders (OpenGL ES 3+)
- if (mRenderer->isES3Capable())
+ auto swizzleShaderIt = mSwizzleShaderMap.find(swizzleShaderType);
+ if (swizzleShaderIt != mSwizzleShaderMap.end())
{
- add3DBlitShaderToMap(GL_RGBA, false, d3d11::CompilePS(device, g_PS_PassthroughRGBA3D, "Blit11 3D RGBA pixel shader" ));
- add3DBlitShaderToMap(GL_RGBA_INTEGER, false, d3d11::CompilePS(device, g_PS_PassthroughRGBA3DUI, "Blit11 3D UI RGBA pixel shader" ));
- add3DBlitShaderToMap(GL_RGBA_INTEGER, true, d3d11::CompilePS(device, g_PS_PassthroughRGBA3DI, "Blit11 3D I RGBA pixel shader" ));
- add3DBlitShaderToMap(GL_BGRA_EXT, false, d3d11::CompilePS(device, g_PS_PassthroughRGBA3D, "Blit11 3D BGRA pixel shader" ));
- add3DBlitShaderToMap(GL_RGB, false, d3d11::CompilePS(device, g_PS_PassthroughRGB3D, "Blit11 3D RGB pixel shader" ));
- add3DBlitShaderToMap(GL_RGB_INTEGER, false, d3d11::CompilePS(device, g_PS_PassthroughRGB3DUI, "Blit11 3D RGB UI pixel shader" ));
- add3DBlitShaderToMap(GL_RGB_INTEGER, true, d3d11::CompilePS(device, g_PS_PassthroughRGB3DI, "Blit11 3D RGB I pixel shader" ));
- add3DBlitShaderToMap(GL_RG, false, d3d11::CompilePS(device, g_PS_PassthroughRG3D, "Blit11 3D RG pixel shader" ));
- add3DBlitShaderToMap(GL_RG_INTEGER, false, d3d11::CompilePS(device, g_PS_PassthroughRG3DUI, "Blit11 3D RG UI pixel shader" ));
- add3DBlitShaderToMap(GL_RG_INTEGER, true, d3d11::CompilePS(device, g_PS_PassthroughRG3DI, "Blit11 3D RG I pixel shader" ));
- add3DBlitShaderToMap(GL_RED, false, d3d11::CompilePS(device, g_PS_PassthroughR3D, "Blit11 3D R pixel shader" ));
- add3DBlitShaderToMap(GL_RED_INTEGER, false, d3d11::CompilePS(device, g_PS_PassthroughR3DUI, "Blit11 3D R UI pixel shader" ));
- add3DBlitShaderToMap(GL_RED_INTEGER, true, d3d11::CompilePS(device, g_PS_PassthroughR3DI, "Blit11 3D R I pixel shader" ));
- add3DBlitShaderToMap(GL_ALPHA, false, d3d11::CompilePS(device, g_PS_PassthroughRGBA3D, "Blit11 3D alpha pixel shader" ));
- add3DBlitShaderToMap(GL_LUMINANCE, false, d3d11::CompilePS(device, g_PS_PassthroughLum3D, "Blit11 3D luminance pixel shader" ));
- add3DBlitShaderToMap(GL_LUMINANCE_ALPHA, false, d3d11::CompilePS(device, g_PS_PassthroughLumAlpha3D, "Blit11 3D luminance alpha pixel shader"));
+ *shader = &swizzleShaderIt->second;
+ return gl::Error(GL_NO_ERROR);
}
// Swizzling shaders (OpenGL ES 3+)
- if (mRenderer->isES3Capable())
- {
- addSwizzleShaderToMap(GL_FLOAT, D3D_SRV_DIMENSION_TEXTURE2D, d3d11::CompilePS(device, g_PS_SwizzleF2D, "Blit11 2D F swizzle pixel shader" ));
- addSwizzleShaderToMap(GL_UNSIGNED_INT, D3D_SRV_DIMENSION_TEXTURE2D, d3d11::CompilePS(device, g_PS_SwizzleUI2D, "Blit11 2D UI swizzle pixel shader"));
- addSwizzleShaderToMap(GL_INT, D3D_SRV_DIMENSION_TEXTURE2D, d3d11::CompilePS(device, g_PS_SwizzleI2D, "Blit11 2D I swizzle pixel shader" ));
-
- addSwizzleShaderToMap(GL_FLOAT, D3D_SRV_DIMENSION_TEXTURECUBE, d3d11::CompilePS(device, g_PS_SwizzleF2DArray, "Blit11 2D Cube F swizzle pixel shader" ));
- addSwizzleShaderToMap(GL_UNSIGNED_INT, D3D_SRV_DIMENSION_TEXTURECUBE, d3d11::CompilePS(device, g_PS_SwizzleUI2DArray, "Blit11 2D Cube UI swizzle pixel shader"));
- addSwizzleShaderToMap(GL_INT, D3D_SRV_DIMENSION_TEXTURECUBE, d3d11::CompilePS(device, g_PS_SwizzleI2DArray, "Blit11 2D Cube I swizzle pixel shader" ));
+ ASSERT(mRenderer->isES3Capable());
- addSwizzleShaderToMap(GL_FLOAT, D3D_SRV_DIMENSION_TEXTURE3D, d3d11::CompilePS(device, g_PS_SwizzleF3D, "Blit11 3D F swizzle pixel shader" ));
- addSwizzleShaderToMap(GL_UNSIGNED_INT, D3D_SRV_DIMENSION_TEXTURE3D, d3d11::CompilePS(device, g_PS_SwizzleUI3D, "Blit11 3D UI swizzle pixel shader"));
- addSwizzleShaderToMap(GL_INT, D3D_SRV_DIMENSION_TEXTURE3D, d3d11::CompilePS(device, g_PS_SwizzleI3D, "Blit11 3D I swizzle pixel shader" ));
-
- addSwizzleShaderToMap(GL_FLOAT, D3D_SRV_DIMENSION_TEXTURE2DARRAY, d3d11::CompilePS(device, g_PS_SwizzleF2DArray, "Blit11 2D Array F swizzle pixel shader" ));
- addSwizzleShaderToMap(GL_UNSIGNED_INT, D3D_SRV_DIMENSION_TEXTURE2DARRAY, d3d11::CompilePS(device, g_PS_SwizzleUI2DArray, "Blit11 2D Array UI swizzle pixel shader"));
- addSwizzleShaderToMap(GL_INT, D3D_SRV_DIMENSION_TEXTURE2DARRAY, d3d11::CompilePS(device, g_PS_SwizzleI2DArray, "Blit11 2D Array I swizzle pixel shader" ));
- }
-}
+ ID3D11Device *device = mRenderer->getDevice();
-void Blit11::clearShaderMap()
-{
- for (BlitShaderMap::iterator i = mBlitShaderMap.begin(); i != mBlitShaderMap.end(); ++i)
+ switch (swizzleShaderType)
{
- Shader &shader = i->second;
- SafeRelease(shader.mPixelShader);
+ case SWIZZLESHADER_2D_FLOAT:
+ addSwizzleShaderToMap(swizzleShaderType, SHADER_2D, d3d11::CompilePS(device, g_PS_SwizzleF2D, "Blit11 2D F swizzle pixel shader"));
+ break;
+ case SWIZZLESHADER_2D_UINT:
+ addSwizzleShaderToMap(swizzleShaderType, SHADER_2D, d3d11::CompilePS(device, g_PS_SwizzleUI2D, "Blit11 2D UI swizzle pixel shader"));
+ break;
+ case SWIZZLESHADER_2D_INT:
+ addSwizzleShaderToMap(swizzleShaderType, SHADER_2D, d3d11::CompilePS(device, g_PS_SwizzleI2D, "Blit11 2D I swizzle pixel shader"));
+ break;
+ case SWIZZLESHADER_CUBE_FLOAT:
+ addSwizzleShaderToMap(swizzleShaderType, SHADER_3D, d3d11::CompilePS(device, g_PS_SwizzleF2DArray, "Blit11 2D Cube F swizzle pixel shader"));
+ break;
+ case SWIZZLESHADER_CUBE_UINT:
+ addSwizzleShaderToMap(swizzleShaderType, SHADER_3D, d3d11::CompilePS(device, g_PS_SwizzleUI2DArray, "Blit11 2D Cube UI swizzle pixel shader"));
+ break;
+ case SWIZZLESHADER_CUBE_INT:
+ addSwizzleShaderToMap(swizzleShaderType, SHADER_3D, d3d11::CompilePS(device, g_PS_SwizzleI2DArray, "Blit11 2D Cube I swizzle pixel shader"));
+ break;
+ case SWIZZLESHADER_3D_FLOAT:
+ addSwizzleShaderToMap(swizzleShaderType, SHADER_3D, d3d11::CompilePS(device, g_PS_SwizzleF3D, "Blit11 3D F swizzle pixel shader"));
+ break;
+ case SWIZZLESHADER_3D_UINT:
+ addSwizzleShaderToMap(swizzleShaderType, SHADER_3D, d3d11::CompilePS(device, g_PS_SwizzleUI3D, "Blit11 3D UI swizzle pixel shader"));
+ break;
+ case SWIZZLESHADER_3D_INT:
+ addSwizzleShaderToMap(swizzleShaderType, SHADER_3D, d3d11::CompilePS(device, g_PS_SwizzleI3D, "Blit11 3D I swizzle pixel shader"));
+ break;
+ case SWIZZLESHADER_ARRAY_FLOAT:
+ addSwizzleShaderToMap(swizzleShaderType, SHADER_3D, d3d11::CompilePS(device, g_PS_SwizzleF2DArray, "Blit11 2D Array F swizzle pixel shader"));
+ break;
+ case SWIZZLESHADER_ARRAY_UINT:
+ addSwizzleShaderToMap(swizzleShaderType, SHADER_3D, d3d11::CompilePS(device, g_PS_SwizzleUI2DArray, "Blit11 2D Array UI swizzle pixel shader"));
+ break;
+ case SWIZZLESHADER_ARRAY_INT:
+ addSwizzleShaderToMap(swizzleShaderType, SHADER_3D, d3d11::CompilePS(device, g_PS_SwizzleI2DArray, "Blit11 2D Array I swizzle pixel shader"));
+ break;
+ default:
+ UNREACHABLE();
+ return gl::Error(GL_INVALID_OPERATION, "Internal error");
}
- mBlitShaderMap.clear();
- for (SwizzleShaderMap::iterator i = mSwizzleShaderMap.begin(); i != mSwizzleShaderMap.end(); ++i)
- {
- Shader &shader = i->second;
- SafeRelease(shader.mPixelShader);
- }
- mSwizzleShaderMap.clear();
+ swizzleShaderIt = mSwizzleShaderMap.find(swizzleShaderType);
+ ASSERT(swizzleShaderIt != mSwizzleShaderMap.end());
+ *shader = &swizzleShaderIt->second;
+ return gl::Error(GL_NO_ERROR);
}
}
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Blit11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Blit11.h
index d3a8c2c8a3..906616131e 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Blit11.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Blit11.h
@@ -12,6 +12,7 @@
#include "common/angleutils.h"
#include "libANGLE/angletypes.h"
#include "libANGLE/Error.h"
+#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h"
#include <map>
@@ -28,9 +29,16 @@ class Blit11 : angle::NonCopyable
gl::Error swizzleTexture(ID3D11ShaderResourceView *source, ID3D11RenderTargetView *dest, const gl::Extents &size,
GLenum swizzleRed, GLenum swizzleGreen, GLenum swizzleBlue, GLenum swizzleAlpha);
- gl::Error copyTexture(ID3D11ShaderResourceView *source, const gl::Box &sourceArea, const gl::Extents &sourceSize,
- ID3D11RenderTargetView *dest, const gl::Box &destArea, const gl::Extents &destSize,
- const gl::Rectangle *scissor, GLenum destFormat, GLenum filter);
+ gl::Error copyTexture(ID3D11ShaderResourceView *source,
+ const gl::Box &sourceArea,
+ const gl::Extents &sourceSize,
+ ID3D11RenderTargetView *dest,
+ const gl::Box &destArea,
+ const gl::Extents &destSize,
+ const gl::Rectangle *scissor,
+ GLenum destFormat,
+ GLenum filter,
+ bool maskOffAlpha);
gl::Error copyStencil(ID3D11Resource *source, unsigned int sourceSubresource, const gl::Box &sourceArea, const gl::Extents &sourceSize,
ID3D11Resource *dest, unsigned int destSubresource, const gl::Box &destArea, const gl::Extents &destSize,
@@ -45,59 +53,112 @@ class Blit11 : angle::NonCopyable
const gl::Rectangle *scissor);
private:
- Renderer11 *mRenderer;
-
- struct BlitParameters
+ enum BlitShaderType
{
- GLenum mDestinationFormat;
- bool mSignedInteger;
- bool m3DBlit;
+ BLITSHADER_INVALID,
+ BLITSHADER_2D_RGBAF,
+ BLITSHADER_2D_BGRAF,
+ BLITSHADER_2D_RGBF,
+ BLITSHADER_2D_RGF,
+ BLITSHADER_2D_RF,
+ BLITSHADER_2D_ALPHA,
+ BLITSHADER_2D_LUMA,
+ BLITSHADER_2D_LUMAALPHA,
+ BLITSHADER_2D_RGBAUI,
+ BLITSHADER_2D_RGBAI,
+ BLITSHADER_2D_RGBUI,
+ BLITSHADER_2D_RGBI,
+ BLITSHADER_2D_RGUI,
+ BLITSHADER_2D_RGI,
+ BLITSHADER_2D_RUI,
+ BLITSHADER_2D_RI,
+ BLITSHADER_3D_RGBAF,
+ BLITSHADER_3D_RGBAUI,
+ BLITSHADER_3D_RGBAI,
+ BLITSHADER_3D_BGRAF,
+ BLITSHADER_3D_RGBF,
+ BLITSHADER_3D_RGBUI,
+ BLITSHADER_3D_RGBI,
+ BLITSHADER_3D_RGF,
+ BLITSHADER_3D_RGUI,
+ BLITSHADER_3D_RGI,
+ BLITSHADER_3D_RF,
+ BLITSHADER_3D_RUI,
+ BLITSHADER_3D_RI,
+ BLITSHADER_3D_ALPHA,
+ BLITSHADER_3D_LUMA,
+ BLITSHADER_3D_LUMAALPHA,
};
- gl::Error copyDepthStencil(ID3D11Resource *source, unsigned int sourceSubresource, const gl::Box &sourceArea, const gl::Extents &sourceSize,
- ID3D11Resource *dest, unsigned int destSubresource, const gl::Box &destArea, const gl::Extents &destSize,
- const gl::Rectangle *scissor, bool stencilOnly);
-
- static bool compareBlitParameters(const BlitParameters &a, const BlitParameters &b);
+ enum SwizzleShaderType
+ {
+ SWIZZLESHADER_INVALID,
+ SWIZZLESHADER_2D_FLOAT,
+ SWIZZLESHADER_2D_UINT,
+ SWIZZLESHADER_2D_INT,
+ SWIZZLESHADER_CUBE_FLOAT,
+ SWIZZLESHADER_CUBE_UINT,
+ SWIZZLESHADER_CUBE_INT,
+ SWIZZLESHADER_3D_FLOAT,
+ SWIZZLESHADER_3D_UINT,
+ SWIZZLESHADER_3D_INT,
+ SWIZZLESHADER_ARRAY_FLOAT,
+ SWIZZLESHADER_ARRAY_UINT,
+ SWIZZLESHADER_ARRAY_INT,
+ };
typedef void (*WriteVertexFunction)(const gl::Box &sourceArea, const gl::Extents &sourceSize,
const gl::Box &destArea, const gl::Extents &destSize,
void *outVertices, unsigned int *outStride, unsigned int *outVertexCount,
D3D11_PRIMITIVE_TOPOLOGY *outTopology);
- struct Shader
+ enum ShaderDimension
{
- WriteVertexFunction mVertexWriteFunction;
- ID3D11InputLayout *mInputLayout;
- ID3D11VertexShader *mVertexShader;
- ID3D11GeometryShader *mGeometryShader;
- ID3D11PixelShader *mPixelShader;
+ SHADER_2D,
+ SHADER_3D,
};
- typedef bool (*BlitParametersComparisonFunction)(const BlitParameters&, const BlitParameters &);
- typedef std::map<BlitParameters, Shader, BlitParametersComparisonFunction> BlitShaderMap;
- BlitShaderMap mBlitShaderMap;
-
- void add2DBlitShaderToMap(GLenum destFormat, bool signedInteger, ID3D11PixelShader *ps);
- void add3DBlitShaderToMap(GLenum destFormat, bool signedInteger, ID3D11PixelShader *ps);
+ struct Shader
+ {
+ ShaderDimension dimension;
+ ID3D11PixelShader *pixelShader;
+ };
- struct SwizzleParameters
+ struct ShaderSupport
{
- GLenum mDestinationType;
- D3D11_SRV_DIMENSION mViewDimension;
+ ID3D11InputLayout *inputLayout;
+ ID3D11VertexShader *vertexShader;
+ ID3D11GeometryShader *geometryShader;
+ WriteVertexFunction vertexWriteFunction;
};
- static bool compareSwizzleParameters(const SwizzleParameters &a, const SwizzleParameters &b);
+ gl::Error initResources();
+ void freeResources();
+
+ ShaderSupport getShaderSupport(const Shader &shader);
+
+ static BlitShaderType GetBlitShaderType(GLenum destinationFormat, bool isSigned, ShaderDimension dimension);
+ static SwizzleShaderType GetSwizzleShaderType(GLenum type, D3D11_SRV_DIMENSION dimensionality);
+
+ gl::Error copyDepthStencil(ID3D11Resource *source, unsigned int sourceSubresource, const gl::Box &sourceArea, const gl::Extents &sourceSize,
+ ID3D11Resource *dest, unsigned int destSubresource, const gl::Box &destArea, const gl::Extents &destSize,
+ const gl::Rectangle *scissor, bool stencilOnly);
+
+ void addBlitShaderToMap(BlitShaderType blitShaderType, ShaderDimension dimension, ID3D11PixelShader *ps);
- typedef bool (*SwizzleParametersComparisonFunction)(const SwizzleParameters&, const SwizzleParameters &);
- typedef std::map<SwizzleParameters, Shader, SwizzleParametersComparisonFunction> SwizzleShaderMap;
- SwizzleShaderMap mSwizzleShaderMap;
+ gl::Error getBlitShader(GLenum destFormat, bool isSigned, ShaderDimension dimension, const Shader **shaderOut);
+ gl::Error getSwizzleShader(GLenum type, D3D11_SRV_DIMENSION viewDimension, const Shader **shaderOut);
- void addSwizzleShaderToMap(GLenum destType, D3D11_SRV_DIMENSION viewDimension, ID3D11PixelShader *ps);
+ void addSwizzleShaderToMap(SwizzleShaderType swizzleShaderType, ShaderDimension dimension, ID3D11PixelShader *ps);
- void buildShaderMap();
void clearShaderMap();
+ Renderer11 *mRenderer;
+
+ std::map<BlitShaderType, Shader> mBlitShaderMap;
+ std::map<SwizzleShaderType, Shader> mSwizzleShaderMap;
+
+ bool mResourcesInitialized;
ID3D11Buffer *mVertexBuffer;
ID3D11SamplerState *mPointSampler;
ID3D11SamplerState *mLinearSampler;
@@ -105,13 +166,15 @@ class Blit11 : angle::NonCopyable
ID3D11RasterizerState *mScissorDisabledRasterizerState;
ID3D11DepthStencilState *mDepthStencilState;
- ID3D11InputLayout *mQuad2DIL;
- ID3D11VertexShader *mQuad2DVS;
- ID3D11PixelShader *mDepthPS;
+ d3d11::LazyInputLayout mQuad2DIL;
+ d3d11::LazyShader<ID3D11VertexShader> mQuad2DVS;
+ d3d11::LazyShader<ID3D11PixelShader> mDepthPS;
+
+ d3d11::LazyInputLayout mQuad3DIL;
+ d3d11::LazyShader<ID3D11VertexShader> mQuad3DVS;
+ d3d11::LazyShader<ID3D11GeometryShader> mQuad3DGS;
- ID3D11InputLayout *mQuad3DIL;
- ID3D11VertexShader *mQuad3DVS;
- ID3D11GeometryShader *mQuad3DGS;
+ d3d11::LazyBlendState mAlphaMaskBlendState;
ID3D11Buffer *mSwizzleCB;
};
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Buffer11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Buffer11.cpp
index d56b0ea7ad..0d5dc08b03 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Buffer11.cpp
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Buffer11.cpp
@@ -8,10 +8,27 @@
#include "libANGLE/renderer/d3d/d3d11/Buffer11.h"
+#include <memory>
+
#include "common/MemoryBuffer.h"
+#include "libANGLE/renderer/d3d/IndexDataManager.h"
+#include "libANGLE/renderer/d3d/VertexDataManager.h"
#include "libANGLE/renderer/d3d/d3d11/Renderer11.h"
+#include "libANGLE/renderer/d3d/d3d11/RenderTarget11.h"
+#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h"
#include "libANGLE/renderer/d3d/d3d11/formatutils11.h"
+namespace
+{
+
+template <typename T>
+GLuint ReadIndexValueFromIndices(const uint8_t *data, size_t index)
+{
+ return reinterpret_cast<const T *>(data)[index];
+}
+typedef GLuint (*ReadIndexValueFunction)(const uint8_t *data, size_t index);
+}
+
#if defined(ANGLE_MINGW32_COMPAT)
typedef enum D3D11_MAP_FLAG {
D3D11_MAP_FLAG_DO_NOT_WAIT = 0x100000
@@ -20,32 +37,33 @@ typedef enum D3D11_MAP_FLAG {
namespace rx
{
-
PackPixelsParams::PackPixelsParams()
- : format(GL_NONE),
- type(GL_NONE),
- outputPitch(0),
- packBuffer(NULL),
- offset(0)
-{}
-
-PackPixelsParams::PackPixelsParams(const gl::Rectangle &areaIn, GLenum formatIn, GLenum typeIn, GLuint outputPitchIn,
- const gl::PixelPackState &packIn, ptrdiff_t offsetIn)
- : area(areaIn),
- format(formatIn),
- type(typeIn),
- outputPitch(outputPitchIn),
- packBuffer(packIn.pixelBuffer.get()),
- pack(packIn.alignment, packIn.reverseRowOrder),
- offset(offsetIn)
-{}
+ : format(GL_NONE), type(GL_NONE), outputPitch(0), packBuffer(nullptr), offset(0)
+{
+}
+
+PackPixelsParams::PackPixelsParams(const gl::Rectangle &areaIn,
+ GLenum formatIn,
+ GLenum typeIn,
+ GLuint outputPitchIn,
+ const gl::PixelPackState &packIn,
+ ptrdiff_t offsetIn)
+ : area(areaIn),
+ format(formatIn),
+ type(typeIn),
+ outputPitch(outputPitchIn),
+ packBuffer(packIn.pixelBuffer.get()),
+ pack(packIn.alignment, packIn.reverseRowOrder),
+ offset(offsetIn)
+{
+}
namespace gl_d3d11
{
D3D11_MAP GetD3DMapTypeFromBits(GLbitfield access)
{
- bool readBit = ((access & GL_MAP_READ_BIT) != 0);
+ bool readBit = ((access & GL_MAP_READ_BIT) != 0);
bool writeBit = ((access & GL_MAP_WRITE_BIT) != 0);
ASSERT(readBit || writeBit);
@@ -71,7 +89,6 @@ D3D11_MAP GetD3DMapTypeFromBits(GLbitfield access)
return D3D11_MAP_READ;
}
}
-
}
// Each instance of Buffer11::BufferStorage is specialized for a class of D3D binding points
@@ -91,8 +108,10 @@ class Buffer11::BufferStorage : angle::NonCopyable
virtual bool isMappable() const = 0;
- virtual bool copyFromStorage(BufferStorage *source, size_t sourceOffset,
- size_t size, size_t destOffset) = 0;
+ virtual bool copyFromStorage(BufferStorage *source,
+ size_t sourceOffset,
+ size_t size,
+ size_t destOffset) = 0;
virtual gl::Error resize(size_t size, bool preserveData) = 0;
virtual uint8_t *map(size_t offset, size_t length, GLbitfield access) = 0;
@@ -120,20 +139,57 @@ class Buffer11::NativeStorage : public Buffer11::BufferStorage
bool isMappable() const override { return mUsage == BUFFER_USAGE_STAGING; }
ID3D11Buffer *getNativeStorage() const { return mNativeStorage; }
-
- bool copyFromStorage(BufferStorage *source, size_t sourceOffset,
- size_t size, size_t destOffset) override;
+ bool copyFromStorage(BufferStorage *source,
+ size_t sourceOffset,
+ size_t size,
+ size_t destOffset) override;
gl::Error resize(size_t size, bool preserveData) override;
uint8_t *map(size_t offset, size_t length, GLbitfield access) override;
void unmap() override;
private:
- static void fillBufferDesc(D3D11_BUFFER_DESC* bufferDesc, Renderer11 *renderer, BufferUsage usage, unsigned int bufferSize);
+ static void fillBufferDesc(D3D11_BUFFER_DESC *bufferDesc,
+ Renderer11 *renderer,
+ BufferUsage usage,
+ unsigned int bufferSize);
ID3D11Buffer *mNativeStorage;
};
+// A emulated indexed buffer storage represents an underlying D3D11 buffer for data
+// that has been expanded to match the indices list used. This storage is only
+// used for FL9_3 pointsprite rendering emulation.
+class Buffer11::EmulatedIndexedStorage : public Buffer11::BufferStorage
+{
+ public:
+ EmulatedIndexedStorage(Renderer11 *renderer);
+ ~EmulatedIndexedStorage() override;
+
+ bool isMappable() const override { return true; }
+
+ ID3D11Buffer *getNativeStorage();
+
+ bool copyFromStorage(BufferStorage *source,
+ size_t sourceOffset,
+ size_t size,
+ size_t destOffset) override;
+
+ gl::Error resize(size_t size, bool preserveData) override;
+
+ uint8_t *map(size_t offset, size_t length, GLbitfield access) override;
+ void unmap() override;
+ bool update(SourceIndexData *indexInfo, const TranslatedAttribute *attribute);
+
+ private:
+ ID3D11Buffer *mNativeStorage; // contains expanded data for use by D3D
+ MemoryBuffer mMemoryBuffer; // original data (not expanded)
+ MemoryBuffer mIndicesMemoryBuffer; // indices data
+ SourceIndexData mIndexInfo; // indices information
+ size_t mAttributeStride; // per element stride in bytes
+ size_t mAttributeOffset; // starting offset
+};
+
// Pack storage represents internal storage for pack buffers. We implement pack buffers
// as CPU memory, tied to a staging texture, for asynchronous texture readback.
class Buffer11::PackStorage : public Buffer11::BufferStorage
@@ -143,24 +199,24 @@ class Buffer11::PackStorage : public Buffer11::BufferStorage
~PackStorage() override;
bool isMappable() const override { return true; }
-
- bool copyFromStorage(BufferStorage *source, size_t sourceOffset,
- size_t size, size_t destOffset) override;
+ bool copyFromStorage(BufferStorage *source,
+ size_t sourceOffset,
+ size_t size,
+ size_t destOffset) override;
gl::Error resize(size_t size, bool preserveData) override;
uint8_t *map(size_t offset, size_t length, GLbitfield access) override;
void unmap() override;
- gl::Error packPixels(ID3D11Texture2D *srcTexure, UINT srcSubresource, const PackPixelsParams &params);
+ gl::Error packPixels(const gl::FramebufferAttachment &readAttachment,
+ const PackPixelsParams &params);
private:
gl::Error flushQueuedPackCommand();
- ID3D11Texture2D *mStagingTexture;
- DXGI_FORMAT mTextureFormat;
- gl::Extents mTextureSize;
+ TextureHelper11 mStagingTexture;
MemoryBuffer mMemoryBuffer;
- PackPixelsParams *mQueuedPackCommand;
+ std::unique_ptr<PackPixelsParams> mQueuedPackCommand;
PackPixelsParams mPackParams;
bool mDataModified;
};
@@ -175,9 +231,10 @@ class Buffer11::SystemMemoryStorage : public Buffer11::BufferStorage
~SystemMemoryStorage() override {}
bool isMappable() const override { return true; }
-
- bool copyFromStorage(BufferStorage *source, size_t sourceOffset,
- size_t size, size_t destOffset) override;
+ bool copyFromStorage(BufferStorage *source,
+ size_t sourceOffset,
+ size_t size,
+ size_t destOffset) override;
gl::Error resize(size_t size, bool preserveData) override;
uint8_t *map(size_t offset, size_t length, GLbitfield access) override;
@@ -193,23 +250,27 @@ Buffer11::Buffer11(Renderer11 *renderer)
: BufferD3D(renderer),
mRenderer(renderer),
mSize(0),
- mMappedStorage(NULL),
- mReadUsageCount(0),
- mHasSystemMemoryStorage(false)
-{}
+ mMappedStorage(nullptr),
+ mBufferStorages(BUFFER_USAGE_COUNT, nullptr),
+ mConstantBufferStorageAdditionalSize(0),
+ mMaxConstantBufferLruCount(0),
+ mReadUsageCount(0)
+{
+}
Buffer11::~Buffer11()
{
- for (auto it = mBufferStorages.begin(); it != mBufferStorages.end(); it++)
+ for (auto &storage : mBufferStorages)
{
- SafeDelete(it->second);
+ SafeDelete(storage);
}
-}
-Buffer11 *Buffer11::makeBuffer11(BufferImpl *buffer)
-{
- ASSERT(HAS_DYNAMIC_TYPE(Buffer11*, buffer));
- return static_cast<Buffer11*>(buffer);
+ for (auto &p : mConstantBufferRangeStoragesCache)
+ {
+ SafeDelete(p.second.storage);
+ }
+
+ mRenderer->onBufferDelete(this);
}
gl::Error Buffer11::setData(const void *data, size_t size, GLenum usage)
@@ -220,18 +281,14 @@ gl::Error Buffer11::setData(const void *data, size_t size, GLenum usage)
return error;
}
- if (usage == GL_STATIC_DRAW)
- {
- initializeStaticData();
- }
-
+ updateD3DBufferUsage(usage);
return error;
}
gl::Error Buffer11::getData(const uint8_t **outData)
{
SystemMemoryStorage *systemMemoryStorage = nullptr;
- gl::Error error = getSystemMemoryStorage(&systemMemoryStorage);
+ gl::Error error = getSystemMemoryStorage(&systemMemoryStorage);
if (error.isError())
{
@@ -310,15 +367,18 @@ gl::Error Buffer11::setSubData(const void *data, size_t size, size_t offset)
}
mSize = std::max(mSize, requiredSize);
- invalidateStaticData();
+ invalidateStaticData(D3D_BUFFER_INVALIDATE_WHOLE_CACHE);
return gl::Error(GL_NO_ERROR);
}
-gl::Error Buffer11::copySubData(BufferImpl* source, GLintptr sourceOffset, GLintptr destOffset, GLsizeiptr size)
+gl::Error Buffer11::copySubData(BufferImpl *source,
+ GLintptr sourceOffset,
+ GLintptr destOffset,
+ GLsizeiptr size)
{
- Buffer11 *sourceBuffer = makeBuffer11(source);
- ASSERT(sourceBuffer != NULL);
+ Buffer11 *sourceBuffer = GetAs<Buffer11>(source);
+ ASSERT(sourceBuffer != nullptr);
BufferStorage *copyDest = getLatestBufferStorage();
if (!copyDest)
@@ -363,19 +423,26 @@ gl::Error Buffer11::copySubData(BufferImpl* source, GLintptr sourceOffset, GLint
copyDest->setDataRevision(copyDest->getDataRevision() + 1);
mSize = std::max<size_t>(mSize, destOffset + size);
- invalidateStaticData();
+ invalidateStaticData(D3D_BUFFER_INVALIDATE_WHOLE_CACHE);
return gl::Error(GL_NO_ERROR);
}
-gl::Error Buffer11::map(size_t offset, size_t length, GLbitfield access, GLvoid **mapPtr)
+gl::Error Buffer11::map(GLenum access, GLvoid **mapPtr)
+{
+ // GL_OES_mapbuffer uses an enum instead of a bitfield for it's access, convert to a bitfield
+ // and call mapRange.
+ ASSERT(access == GL_WRITE_ONLY_OES);
+ return mapRange(0, mSize, GL_MAP_WRITE_BIT, mapPtr);
+}
+
+gl::Error Buffer11::mapRange(size_t offset, size_t length, GLbitfield access, GLvoid **mapPtr)
{
ASSERT(!mMappedStorage);
BufferStorage *latestStorage = getLatestBufferStorage();
- if (latestStorage &&
- (latestStorage->getUsage() == BUFFER_USAGE_PIXEL_PACK ||
- latestStorage->getUsage() == BUFFER_USAGE_STAGING))
+ if (latestStorage && (latestStorage->getUsage() == BUFFER_USAGE_PIXEL_PACK ||
+ latestStorage->getUsage() == BUFFER_USAGE_STAGING))
{
// Latest storage is mappable.
mMappedStorage = latestStorage;
@@ -396,6 +463,7 @@ gl::Error Buffer11::map(size_t offset, size_t length, GLbitfield access, GLvoid
{
// Update the data revision immediately, since the data might be changed at any time
mMappedStorage->setDataRevision(mMappedStorage->getDataRevision() + 1);
+ invalidateStaticData(D3D_BUFFER_INVALIDATE_WHOLE_CACHE);
}
uint8_t *mappedBuffer = mMappedStorage->map(offset, length, access);
@@ -408,24 +476,29 @@ gl::Error Buffer11::map(size_t offset, size_t length, GLbitfield access, GLvoid
return gl::Error(GL_NO_ERROR);
}
-gl::Error Buffer11::unmap()
+gl::Error Buffer11::unmap(GLboolean *result)
{
ASSERT(mMappedStorage);
mMappedStorage->unmap();
- mMappedStorage = NULL;
+ mMappedStorage = nullptr;
+
+ // TODO: detect if we had corruption. if so, return false.
+ *result = GL_TRUE;
+
return gl::Error(GL_NO_ERROR);
}
void Buffer11::markTransformFeedbackUsage()
{
- BufferStorage *transformFeedbackStorage = getBufferStorage(BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK);
+ BufferStorage *transformFeedbackStorage =
+ getBufferStorage(BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK);
if (transformFeedbackStorage)
{
transformFeedbackStorage->setDataRevision(transformFeedbackStorage->getDataRevision() + 1);
}
- invalidateStaticData();
+ invalidateStaticData(D3D_BUFFER_INVALIDATE_WHOLE_CACHE);
}
void Buffer11::markBufferUsage()
@@ -435,14 +508,13 @@ void Buffer11::markBufferUsage()
// Free the system memory storage if we decide it isn't being used very often.
const unsigned int usageLimit = 5;
- if (mReadUsageCount > usageLimit && mHasSystemMemoryStorage)
+ BufferStorage *&sysMemUsage = mBufferStorages[BUFFER_USAGE_SYSTEM_MEMORY];
+ if (mReadUsageCount > usageLimit && sysMemUsage != nullptr)
{
- auto systemMemoryStorageIt = mBufferStorages.find(BUFFER_USAGE_SYSTEM_MEMORY);
- ASSERT(systemMemoryStorageIt != mBufferStorages.end());
-
- SafeDelete(systemMemoryStorageIt->second);
- mBufferStorages.erase(systemMemoryStorageIt);
- mHasSystemMemoryStorage = false;
+ if (getLatestBufferStorage() != sysMemUsage)
+ {
+ SafeDelete(sysMemUsage);
+ }
}
}
@@ -455,12 +527,59 @@ ID3D11Buffer *Buffer11::getBuffer(BufferUsage usage)
if (!bufferStorage)
{
// Storage out-of-memory
- return NULL;
+ return nullptr;
}
- ASSERT(HAS_DYNAMIC_TYPE(NativeStorage*, bufferStorage));
+ return GetAs<NativeStorage>(bufferStorage)->getNativeStorage();
+}
+
+ID3D11Buffer *Buffer11::getEmulatedIndexedBuffer(SourceIndexData *indexInfo,
+ const TranslatedAttribute *attribute)
+{
+ markBufferUsage();
+
+ assert(indexInfo != nullptr);
+ assert(attribute != nullptr);
- return static_cast<NativeStorage*>(bufferStorage)->getNativeStorage();
+ BufferStorage *bufferStorage = getBufferStorage(BUFFER_USAGE_EMULATED_INDEXED_VERTEX);
+ if (!bufferStorage)
+ {
+ // Storage out-of-memory
+ return nullptr;
+ }
+
+ EmulatedIndexedStorage *emulatedStorage = GetAs<EmulatedIndexedStorage>(bufferStorage);
+ if (!emulatedStorage->update(indexInfo, attribute))
+ {
+ // Storage out-of-memory
+ return nullptr;
+ }
+
+ return emulatedStorage->getNativeStorage();
+}
+
+ID3D11Buffer *Buffer11::getConstantBufferRange(GLintptr offset, GLsizeiptr size)
+{
+ markBufferUsage();
+
+ BufferStorage *bufferStorage;
+
+ if (offset == 0)
+ {
+ bufferStorage = getBufferStorage(BUFFER_USAGE_UNIFORM);
+ }
+ else
+ {
+ bufferStorage = getConstantBufferRangeStorage(offset, size);
+ }
+
+ if (!bufferStorage)
+ {
+ // Storage out-of-memory
+ return nullptr;
+ }
+
+ return GetAs<NativeStorage>(bufferStorage)->getNativeStorage();
}
ID3D11ShaderResourceView *Buffer11::getSRV(DXGI_FORMAT srvFormat)
@@ -470,11 +589,10 @@ ID3D11ShaderResourceView *Buffer11::getSRV(DXGI_FORMAT srvFormat)
if (!storage)
{
// Storage out-of-memory
- return NULL;
+ return nullptr;
}
- ASSERT(HAS_DYNAMIC_TYPE(NativeStorage*, storage));
- ID3D11Buffer *buffer = static_cast<NativeStorage*>(storage)->getNativeStorage();
+ ID3D11Buffer *buffer = GetAs<NativeStorage>(storage)->getNativeStorage();
auto bufferSRVIt = mBufferResourceViews.find(srvFormat);
@@ -491,16 +609,17 @@ ID3D11ShaderResourceView *Buffer11::getSRV(DXGI_FORMAT srvFormat)
}
}
- ID3D11Device *device = mRenderer->getDevice();
- ID3D11ShaderResourceView *bufferSRV = NULL;
+ ID3D11Device *device = mRenderer->getDevice();
+ ID3D11ShaderResourceView *bufferSRV = nullptr;
const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(srvFormat);
D3D11_SHADER_RESOURCE_VIEW_DESC bufferSRVDesc;
bufferSRVDesc.Buffer.ElementOffset = 0;
- bufferSRVDesc.Buffer.ElementWidth = mSize / dxgiFormatInfo.pixelBytes;
- bufferSRVDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER;
- bufferSRVDesc.Format = srvFormat;
+ bufferSRVDesc.Buffer.ElementWidth =
+ static_cast<unsigned int>(mSize) / dxgiFormatInfo.pixelBytes;
+ bufferSRVDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER;
+ bufferSRVDesc.Format = srvFormat;
HRESULT result = device->CreateShaderResourceView(buffer, &bufferSRVDesc, &bufferSRV);
UNUSED_ASSERTION_VARIABLE(result);
@@ -511,14 +630,15 @@ ID3D11ShaderResourceView *Buffer11::getSRV(DXGI_FORMAT srvFormat)
return bufferSRV;
}
-gl::Error Buffer11::packPixels(ID3D11Texture2D *srcTexture, UINT srcSubresource, const PackPixelsParams &params)
+gl::Error Buffer11::packPixels(const gl::FramebufferAttachment &readAttachment,
+ const PackPixelsParams &params)
{
- PackStorage *packStorage = getPackStorage();
+ PackStorage *packStorage = getPackStorage();
BufferStorage *latestStorage = getLatestBufferStorage();
if (packStorage)
{
- gl::Error error = packStorage->packPixels(srcTexture, srcSubresource, params);
+ gl::Error error = packStorage->packPixels(readAttachment, params);
if (error.isError())
{
return error;
@@ -529,14 +649,23 @@ gl::Error Buffer11::packPixels(ID3D11Texture2D *srcTexture, UINT srcSubresource,
return gl::Error(GL_NO_ERROR);
}
+size_t Buffer11::getTotalCPUBufferMemoryBytes() const
+{
+ size_t allocationSize = 0;
+
+ BufferStorage *staging = mBufferStorages[BUFFER_USAGE_STAGING];
+ allocationSize += staging ? staging->getSize() : 0;
+
+ BufferStorage *sysMem = mBufferStorages[BUFFER_USAGE_SYSTEM_MEMORY];
+ allocationSize += sysMem ? sysMem->getSize() : 0;
+
+ return allocationSize;
+}
+
Buffer11::BufferStorage *Buffer11::getBufferStorage(BufferUsage usage)
{
- BufferStorage *newStorage = NULL;
- auto directBufferIt = mBufferStorages.find(usage);
- if (directBufferIt != mBufferStorages.end())
- {
- newStorage = directBufferIt->second;
- }
+ ASSERT(0 <= usage && usage < BUFFER_USAGE_COUNT);
+ BufferStorage *&newStorage = mBufferStorages[usage];
if (!newStorage)
{
@@ -547,15 +676,16 @@ Buffer11::BufferStorage *Buffer11::getBufferStorage(BufferUsage usage)
else if (usage == BUFFER_USAGE_SYSTEM_MEMORY)
{
newStorage = new SystemMemoryStorage(mRenderer);
- mHasSystemMemoryStorage = true;
+ }
+ else if (usage == BUFFER_USAGE_EMULATED_INDEXED_VERTEX)
+ {
+ newStorage = new EmulatedIndexedStorage(mRenderer);
}
else
{
// buffer is not allocated, create it
newStorage = new NativeStorage(mRenderer, usage);
}
-
- mBufferStorages.insert(std::make_pair(usage, newStorage));
}
// resize buffer
@@ -564,19 +694,88 @@ Buffer11::BufferStorage *Buffer11::getBufferStorage(BufferUsage usage)
if (newStorage->resize(mSize, true).isError())
{
// Out of memory error
- return NULL;
+ return nullptr;
+ }
+ }
+
+ updateBufferStorage(newStorage, 0, mSize);
+
+ return newStorage;
+}
+
+Buffer11::BufferStorage *Buffer11::getConstantBufferRangeStorage(GLintptr offset, GLsizeiptr size)
+{
+ BufferStorage *newStorage;
+
+ {
+ // Keep the cacheEntry in a limited scope because it may be invalidated later in the code if
+ // we need to reclaim some space.
+ ConstantBufferCacheEntry *cacheEntry = &mConstantBufferRangeStoragesCache[offset];
+
+ if (!cacheEntry->storage)
+ {
+ cacheEntry->storage = new NativeStorage(mRenderer, BUFFER_USAGE_UNIFORM);
+ cacheEntry->lruCount = ++mMaxConstantBufferLruCount;
}
+
+ cacheEntry->lruCount = ++mMaxConstantBufferLruCount;
+ newStorage = cacheEntry->storage;
}
+ if (newStorage->getSize() < static_cast<size_t>(size))
+ {
+ size_t maximumAllowedAdditionalSize = 2 * getSize();
+
+ size_t sizeDelta = size - newStorage->getSize();
+
+ while (mConstantBufferStorageAdditionalSize + sizeDelta > maximumAllowedAdditionalSize)
+ {
+ auto iter = std::min_element(std::begin(mConstantBufferRangeStoragesCache),
+ std::end(mConstantBufferRangeStoragesCache),
+ [](const ConstantBufferCache::value_type &a,
+ const ConstantBufferCache::value_type &b)
+ {
+ return a.second.lruCount < b.second.lruCount;
+ });
+
+ ASSERT(iter->second.storage != newStorage);
+ ASSERT(mConstantBufferStorageAdditionalSize >= iter->second.storage->getSize());
+
+ mConstantBufferStorageAdditionalSize -= iter->second.storage->getSize();
+ SafeDelete(iter->second.storage);
+ mConstantBufferRangeStoragesCache.erase(iter);
+ }
+
+ if (newStorage->resize(size, false).isError())
+ {
+ // Out of memory error
+ return nullptr;
+ }
+
+ mConstantBufferStorageAdditionalSize += sizeDelta;
+
+ // We don't copy the old data when resizing the constant buffer because the data may be
+ // out-of-date therefore we reset the data revision and let updateBufferStorage() handle the
+ // copy.
+ newStorage->setDataRevision(0);
+ }
+
+ updateBufferStorage(newStorage, offset, size);
+
+ return newStorage;
+}
+
+void Buffer11::updateBufferStorage(BufferStorage *storage, size_t sourceOffset, size_t storageSize)
+{
BufferStorage *latestBuffer = getLatestBufferStorage();
- if (latestBuffer && latestBuffer->getDataRevision() > newStorage->getDataRevision())
+ if (latestBuffer && latestBuffer->getDataRevision() > storage->getDataRevision())
{
// Copy through a staging buffer if we're copying from or to a non-staging, mappable
// buffer storage. This is because we can't map a GPU buffer, and copy CPU
// data directly. If we're already using a staging buffer we're fine.
if (latestBuffer->getUsage() != BUFFER_USAGE_STAGING &&
- newStorage->getUsage() != BUFFER_USAGE_STAGING &&
- (!latestBuffer->isMappable() || !newStorage->isMappable()))
+ storage->getUsage() != BUFFER_USAGE_STAGING &&
+ (!latestBuffer->isMappable() || !storage->isMappable()))
{
NativeStorage *stagingBuffer = getStagingStorage();
@@ -588,28 +787,25 @@ Buffer11::BufferStorage *Buffer11::getBufferStorage(BufferUsage usage)
// if copyFromStorage returns true, the D3D buffer has been recreated
// and we should update our serial
- if (newStorage->copyFromStorage(latestBuffer, 0, latestBuffer->getSize(), 0))
+ if (storage->copyFromStorage(latestBuffer, sourceOffset, storageSize, 0))
{
updateSerial();
}
- newStorage->setDataRevision(latestBuffer->getDataRevision());
+ storage->setDataRevision(latestBuffer->getDataRevision());
}
-
- return newStorage;
}
Buffer11::BufferStorage *Buffer11::getLatestBufferStorage() const
{
// Even though we iterate over all the direct buffers, it is expected that only
// 1 or 2 will be present.
- BufferStorage *latestStorage = NULL;
+ BufferStorage *latestStorage = nullptr;
DataRevision latestRevision = 0;
- for (auto it = mBufferStorages.begin(); it != mBufferStorages.end(); it++)
+ for (auto &storage : mBufferStorages)
{
- BufferStorage *storage = it->second;
- if (!latestStorage || storage->getDataRevision() > latestRevision)
+ if (storage && (!latestStorage || storage->getDataRevision() > latestRevision))
{
- latestStorage = storage;
+ latestStorage = storage;
latestRevision = storage->getDataRevision();
}
}
@@ -620,7 +816,7 @@ Buffer11::BufferStorage *Buffer11::getLatestBufferStorage() const
if (latestStorage->resize(mSize, true).isError())
{
// Out of memory error
- return NULL;
+ return nullptr;
}
}
@@ -634,11 +830,10 @@ Buffer11::NativeStorage *Buffer11::getStagingStorage()
if (!stagingStorage)
{
// Out-of-memory
- return NULL;
+ return nullptr;
}
- ASSERT(HAS_DYNAMIC_TYPE(NativeStorage*, stagingStorage));
- return static_cast<NativeStorage*>(stagingStorage);
+ return GetAs<NativeStorage>(stagingStorage);
}
Buffer11::PackStorage *Buffer11::getPackStorage()
@@ -648,11 +843,10 @@ Buffer11::PackStorage *Buffer11::getPackStorage()
if (!packStorage)
{
// Out-of-memory
- return NULL;
+ return nullptr;
}
- ASSERT(HAS_DYNAMIC_TYPE(PackStorage*, packStorage));
- return static_cast<PackStorage*>(packStorage);
+ return GetAs<PackStorage>(packStorage);
}
bool Buffer11::supportsDirectBinding() const
@@ -664,10 +858,7 @@ bool Buffer11::supportsDirectBinding() const
}
Buffer11::BufferStorage::BufferStorage(Renderer11 *renderer, BufferUsage usage)
- : mRenderer(renderer),
- mUsage(usage),
- mRevision(0),
- mBufferSize(0)
+ : mRenderer(renderer), mRevision(0), mUsage(usage), mBufferSize(0)
{
}
@@ -689,8 +880,7 @@ gl::Error Buffer11::BufferStorage::setData(const uint8_t *data, size_t offset, s
}
Buffer11::NativeStorage::NativeStorage(Renderer11 *renderer, BufferUsage usage)
- : BufferStorage(renderer, usage),
- mNativeStorage(NULL)
+ : BufferStorage(renderer, usage), mNativeStorage(nullptr)
{
}
@@ -700,19 +890,21 @@ Buffer11::NativeStorage::~NativeStorage()
}
// Returns true if it recreates the direct buffer
-bool Buffer11::NativeStorage::copyFromStorage(BufferStorage *source, size_t sourceOffset,
- size_t size, size_t destOffset)
+bool Buffer11::NativeStorage::copyFromStorage(BufferStorage *source,
+ size_t sourceOffset,
+ size_t size,
+ size_t destOffset)
{
ID3D11DeviceContext *context = mRenderer->getDeviceContext();
- size_t requiredSize = sourceOffset + size;
- bool createBuffer = !mNativeStorage || mBufferSize < requiredSize;
+ size_t requiredSize = destOffset + size;
+ bool createBuffer = !mNativeStorage || mBufferSize < requiredSize;
// (Re)initialize D3D buffer if needed
if (createBuffer)
{
bool preserveData = (destOffset > 0);
- resize(source->getSize(), preserveData);
+ resize(requiredSize, preserveData);
}
if (source->getUsage() == BUFFER_USAGE_PIXEL_PACK ||
@@ -724,8 +916,12 @@ bool Buffer11::NativeStorage::copyFromStorage(BufferStorage *source, size_t sour
D3D11_MAPPED_SUBRESOURCE mappedResource;
HRESULT hr = context->Map(mNativeStorage, 0, D3D11_MAP_WRITE, 0, &mappedResource);
- UNUSED_ASSERTION_VARIABLE(hr);
ASSERT(SUCCEEDED(hr));
+ if (FAILED(hr))
+ {
+ source->unmap();
+ return false;
+ }
uint8_t *destPointer = static_cast<uint8_t *>(mappedResource.pData) + destOffset;
@@ -738,20 +934,18 @@ bool Buffer11::NativeStorage::copyFromStorage(BufferStorage *source, size_t sour
}
else
{
- ASSERT(HAS_DYNAMIC_TYPE(NativeStorage*, source));
-
D3D11_BOX srcBox;
- srcBox.left = sourceOffset;
- srcBox.right = sourceOffset + size;
- srcBox.top = 0;
+ srcBox.left = static_cast<unsigned int>(sourceOffset);
+ srcBox.right = static_cast<unsigned int>(sourceOffset + size);
+ srcBox.top = 0;
srcBox.bottom = 1;
- srcBox.front = 0;
- srcBox.back = 1;
+ srcBox.front = 0;
+ srcBox.back = 1;
- ASSERT(HAS_DYNAMIC_TYPE(NativeStorage*, source));
- ID3D11Buffer *sourceBuffer = static_cast<NativeStorage*>(source)->getNativeStorage();
+ ID3D11Buffer *sourceBuffer = GetAs<NativeStorage>(source)->getNativeStorage();
- context->CopySubresourceRegion(mNativeStorage, 0, destOffset, 0, 0, sourceBuffer, 0, &srcBox);
+ context->CopySubresourceRegion(mNativeStorage, 0, static_cast<unsigned int>(destOffset), 0,
+ 0, sourceBuffer, 0, &srcBox);
}
return createBuffer;
@@ -759,32 +953,35 @@ bool Buffer11::NativeStorage::copyFromStorage(BufferStorage *source, size_t sour
gl::Error Buffer11::NativeStorage::resize(size_t size, bool preserveData)
{
- ID3D11Device *device = mRenderer->getDevice();
+ ID3D11Device *device = mRenderer->getDevice();
ID3D11DeviceContext *context = mRenderer->getDeviceContext();
D3D11_BUFFER_DESC bufferDesc;
- fillBufferDesc(&bufferDesc, mRenderer, mUsage, size);
+ fillBufferDesc(&bufferDesc, mRenderer, mUsage, static_cast<unsigned int>(size));
ID3D11Buffer *newBuffer;
- HRESULT result = device->CreateBuffer(&bufferDesc, NULL, &newBuffer);
+ HRESULT result = device->CreateBuffer(&bufferDesc, nullptr, &newBuffer);
if (FAILED(result))
{
- return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal buffer, result: 0x%X.", result);
+ return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal buffer, result: 0x%X.",
+ result);
}
+ d3d11::SetDebugName(newBuffer, "Buffer11::NativeStorage");
+
if (mNativeStorage && preserveData)
{
// We don't call resize if the buffer is big enough already.
ASSERT(mBufferSize <= size);
D3D11_BOX srcBox;
- srcBox.left = 0;
- srcBox.right = mBufferSize;
- srcBox.top = 0;
+ srcBox.left = 0;
+ srcBox.right = static_cast<unsigned int>(mBufferSize);
+ srcBox.top = 0;
srcBox.bottom = 1;
- srcBox.front = 0;
- srcBox.back = 1;
+ srcBox.front = 0;
+ srcBox.back = 1;
context->CopySubresourceRegion(newBuffer, 0, 0, 0, 0, mNativeStorage, 0, &srcBox);
}
@@ -798,58 +995,62 @@ gl::Error Buffer11::NativeStorage::resize(size_t size, bool preserveData)
return gl::Error(GL_NO_ERROR);
}
-void Buffer11::NativeStorage::fillBufferDesc(D3D11_BUFFER_DESC* bufferDesc, Renderer11 *renderer,
- BufferUsage usage, unsigned int bufferSize)
+void Buffer11::NativeStorage::fillBufferDesc(D3D11_BUFFER_DESC *bufferDesc,
+ Renderer11 *renderer,
+ BufferUsage usage,
+ unsigned int bufferSize)
{
- bufferDesc->ByteWidth = bufferSize;
- bufferDesc->MiscFlags = 0;
+ bufferDesc->ByteWidth = bufferSize;
+ bufferDesc->MiscFlags = 0;
bufferDesc->StructureByteStride = 0;
switch (usage)
{
- case BUFFER_USAGE_STAGING:
- bufferDesc->Usage = D3D11_USAGE_STAGING;
- bufferDesc->BindFlags = 0;
- bufferDesc->CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
- break;
+ case BUFFER_USAGE_STAGING:
+ bufferDesc->Usage = D3D11_USAGE_STAGING;
+ bufferDesc->BindFlags = 0;
+ bufferDesc->CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
+ break;
- case BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK:
- bufferDesc->Usage = D3D11_USAGE_DEFAULT;
- bufferDesc->BindFlags = D3D11_BIND_VERTEX_BUFFER;
+ case BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK:
+ bufferDesc->Usage = D3D11_USAGE_DEFAULT;
+ bufferDesc->BindFlags = D3D11_BIND_VERTEX_BUFFER;
- if (renderer->isES3Capable())
- {
- bufferDesc->BindFlags |= D3D11_BIND_STREAM_OUTPUT;
- }
+ if (renderer->isES3Capable())
+ {
+ bufferDesc->BindFlags |= D3D11_BIND_STREAM_OUTPUT;
+ }
- bufferDesc->CPUAccessFlags = 0;
- break;
-
- case BUFFER_USAGE_INDEX:
- bufferDesc->Usage = D3D11_USAGE_DEFAULT;
- bufferDesc->BindFlags = D3D11_BIND_INDEX_BUFFER;
- bufferDesc->CPUAccessFlags = 0;
- break;
-
- case BUFFER_USAGE_PIXEL_UNPACK:
- bufferDesc->Usage = D3D11_USAGE_DEFAULT;
- bufferDesc->BindFlags = D3D11_BIND_SHADER_RESOURCE;
- bufferDesc->CPUAccessFlags = 0;
- break;
-
- case BUFFER_USAGE_UNIFORM:
- bufferDesc->Usage = D3D11_USAGE_DYNAMIC;
- bufferDesc->BindFlags = D3D11_BIND_CONSTANT_BUFFER;
- bufferDesc->CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
-
- // Constant buffers must be of a limited size, and aligned to 16 byte boundaries
- // For our purposes we ignore any buffer data past the maximum constant buffer size
- bufferDesc->ByteWidth = roundUp(bufferDesc->ByteWidth, 16u);
- bufferDesc->ByteWidth = std::min<UINT>(bufferDesc->ByteWidth, renderer->getRendererCaps().maxUniformBlockSize);
- break;
-
- default:
- UNREACHABLE();
+ bufferDesc->CPUAccessFlags = 0;
+ break;
+
+ case BUFFER_USAGE_INDEX:
+ bufferDesc->Usage = D3D11_USAGE_DEFAULT;
+ bufferDesc->BindFlags = D3D11_BIND_INDEX_BUFFER;
+ bufferDesc->CPUAccessFlags = 0;
+ break;
+
+ case BUFFER_USAGE_PIXEL_UNPACK:
+ bufferDesc->Usage = D3D11_USAGE_DEFAULT;
+ bufferDesc->BindFlags = D3D11_BIND_SHADER_RESOURCE;
+ bufferDesc->CPUAccessFlags = 0;
+ break;
+
+ case BUFFER_USAGE_UNIFORM:
+ bufferDesc->Usage = D3D11_USAGE_DYNAMIC;
+ bufferDesc->BindFlags = D3D11_BIND_CONSTANT_BUFFER;
+ bufferDesc->CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
+
+ // Constant buffers must be of a limited size, and aligned to 16 byte boundaries
+ // For our purposes we ignore any buffer data past the maximum constant buffer size
+ bufferDesc->ByteWidth = roundUp(bufferDesc->ByteWidth, 16u);
+ bufferDesc->ByteWidth =
+ std::min<UINT>(bufferDesc->ByteWidth,
+ static_cast<UINT>(renderer->getRendererCaps().maxUniformBlockSize));
+ break;
+
+ default:
+ UNREACHABLE();
}
}
@@ -859,14 +1060,16 @@ uint8_t *Buffer11::NativeStorage::map(size_t offset, size_t length, GLbitfield a
D3D11_MAPPED_SUBRESOURCE mappedResource;
ID3D11DeviceContext *context = mRenderer->getDeviceContext();
- D3D11_MAP d3dMapType = gl_d3d11::GetD3DMapTypeFromBits(access);
- UINT d3dMapFlag = ((access & GL_MAP_UNSYNCHRONIZED_BIT) != 0 ? D3D11_MAP_FLAG_DO_NOT_WAIT : 0);
+ D3D11_MAP d3dMapType = gl_d3d11::GetD3DMapTypeFromBits(access);
+ UINT d3dMapFlag = ((access & GL_MAP_UNSYNCHRONIZED_BIT) != 0 ? D3D11_MAP_FLAG_DO_NOT_WAIT : 0);
HRESULT result = context->Map(mNativeStorage, 0, d3dMapType, d3dMapFlag, &mappedResource);
- UNUSED_ASSERTION_VARIABLE(result);
ASSERT(SUCCEEDED(result));
-
- return static_cast<uint8_t*>(mappedResource.pData) + offset;
+ if (FAILED(result))
+ {
+ return nullptr;
+ }
+ return static_cast<uint8_t *>(mappedResource.pData) + offset;
}
void Buffer11::NativeStorage::unmap()
@@ -876,23 +1079,189 @@ void Buffer11::NativeStorage::unmap()
context->Unmap(mNativeStorage, 0);
}
+Buffer11::EmulatedIndexedStorage::EmulatedIndexedStorage(Renderer11 *renderer)
+ : BufferStorage(renderer, BUFFER_USAGE_EMULATED_INDEXED_VERTEX), mNativeStorage(nullptr)
+{
+}
+
+Buffer11::EmulatedIndexedStorage::~EmulatedIndexedStorage()
+{
+ SafeRelease(mNativeStorage);
+}
+
+ID3D11Buffer *Buffer11::EmulatedIndexedStorage::getNativeStorage()
+{
+ if (!mNativeStorage)
+ {
+ // Expand the memory storage upon request and cache the results.
+ unsigned int expandedDataSize =
+ static_cast<unsigned int>((mIndexInfo.srcCount * mAttributeStride) + mAttributeOffset);
+ MemoryBuffer expandedData;
+ if (!expandedData.resize(expandedDataSize))
+ {
+ return nullptr;
+ }
+
+ // Clear the contents of the allocated buffer
+ ZeroMemory(expandedData.data(), expandedDataSize);
+
+ uint8_t *curr = expandedData.data();
+ const uint8_t *ptr = static_cast<const uint8_t *>(mIndexInfo.srcIndices);
+
+ // Ensure that we start in the correct place for the emulated data copy operation to
+ // maintain offset behaviors.
+ curr += mAttributeOffset;
+
+ ReadIndexValueFunction readIndexValue = ReadIndexValueFromIndices<GLushort>;
+
+ switch (mIndexInfo.srcIndexType)
+ {
+ case GL_UNSIGNED_INT:
+ readIndexValue = ReadIndexValueFromIndices<GLuint>;
+ break;
+ case GL_UNSIGNED_SHORT:
+ readIndexValue = ReadIndexValueFromIndices<GLushort>;
+ break;
+ case GL_UNSIGNED_BYTE:
+ readIndexValue = ReadIndexValueFromIndices<GLubyte>;
+ break;
+ }
+
+ // Iterate over the cached index data and copy entries indicated into the emulated buffer.
+ for (GLuint i = 0; i < mIndexInfo.srcCount; i++)
+ {
+ GLuint idx = readIndexValue(ptr, i);
+ memcpy(curr, mMemoryBuffer.data() + (mAttributeStride * idx), mAttributeStride);
+ curr += mAttributeStride;
+ }
+
+ // Finally, initialize the emulated indexed native storage object with the newly copied data
+ // and free the temporary buffers used.
+ ID3D11Device *device = mRenderer->getDevice();
+
+ D3D11_BUFFER_DESC bufferDesc;
+ bufferDesc.ByteWidth = expandedDataSize;
+ bufferDesc.MiscFlags = 0;
+ bufferDesc.StructureByteStride = 0;
+ bufferDesc.Usage = D3D11_USAGE_DEFAULT;
+ bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
+ bufferDesc.CPUAccessFlags = 0;
+
+ D3D11_SUBRESOURCE_DATA subResourceData = {expandedData.data(), 0, 0};
+
+ HRESULT result = device->CreateBuffer(&bufferDesc, &subResourceData, &mNativeStorage);
+ if (FAILED(result))
+ {
+ ERR("Could not create emulated index data buffer: %08lX", result);
+ return nullptr;
+ }
+ d3d11::SetDebugName(mNativeStorage, "Buffer11::EmulatedIndexedStorage");
+ }
+
+ return mNativeStorage;
+}
+
+bool Buffer11::EmulatedIndexedStorage::update(SourceIndexData *indexInfo,
+ const TranslatedAttribute *attribute)
+{
+ // If a change in the indices applied from the last draw call is detected, then the emulated
+ // indexed buffer needs to be invalidated. After invalidation, the change detected flag should
+ // be cleared to avoid unnecessary recreation of the buffer.
+ if (mNativeStorage == nullptr || indexInfo->srcIndicesChanged)
+ {
+ SafeRelease(mNativeStorage);
+
+ // Copy attribute offset and stride information
+ mAttributeStride = attribute->stride;
+ mAttributeOffset = attribute->offset;
+
+ // Copy the source index data. This ensures that the lifetime of the indices pointer
+ // stays with this storage until the next time we invalidate.
+ size_t indicesDataSize = 0;
+ switch (indexInfo->srcIndexType)
+ {
+ case GL_UNSIGNED_INT:
+ indicesDataSize = sizeof(GLuint) * indexInfo->srcCount;
+ break;
+ case GL_UNSIGNED_SHORT:
+ indicesDataSize = sizeof(GLushort) * indexInfo->srcCount;
+ break;
+ case GL_UNSIGNED_BYTE:
+ indicesDataSize = sizeof(GLubyte) * indexInfo->srcCount;
+ break;
+ default:
+ indicesDataSize = sizeof(GLushort) * indexInfo->srcCount;
+ break;
+ }
+
+ if (!mIndicesMemoryBuffer.resize(indicesDataSize))
+ {
+ return false;
+ }
+
+ memcpy(mIndicesMemoryBuffer.data(), indexInfo->srcIndices, indicesDataSize);
+
+ // Copy the source index data description and update the srcIndices pointer to point
+ // to our cached index data.
+ mIndexInfo = *indexInfo;
+ mIndexInfo.srcIndices = mIndicesMemoryBuffer.data();
+
+ indexInfo->srcIndicesChanged = false;
+ }
+ return true;
+}
+
+bool Buffer11::EmulatedIndexedStorage::copyFromStorage(BufferStorage *source,
+ size_t sourceOffset,
+ size_t size,
+ size_t destOffset)
+{
+ ASSERT(source->isMappable());
+ const uint8_t *sourceData = source->map(sourceOffset, size, GL_MAP_READ_BIT);
+ ASSERT(destOffset + size <= mMemoryBuffer.size());
+ memcpy(mMemoryBuffer.data() + destOffset, sourceData, size);
+ source->unmap();
+ return true;
+}
+
+gl::Error Buffer11::EmulatedIndexedStorage::resize(size_t size, bool preserveData)
+{
+ if (mMemoryBuffer.size() < size)
+ {
+ if (!mMemoryBuffer.resize(size))
+ {
+ return gl::Error(GL_OUT_OF_MEMORY, "Failed to resize EmulatedIndexedStorage");
+ }
+ mBufferSize = size;
+ }
+
+ return gl::Error(GL_NO_ERROR);
+}
+
+uint8_t *Buffer11::EmulatedIndexedStorage::map(size_t offset, size_t length, GLbitfield access)
+{
+ ASSERT(!mMemoryBuffer.empty() && offset + length <= mMemoryBuffer.size());
+ return mMemoryBuffer.data() + offset;
+}
+
+void Buffer11::EmulatedIndexedStorage::unmap()
+{
+ // No-op
+}
+
Buffer11::PackStorage::PackStorage(Renderer11 *renderer)
- : BufferStorage(renderer, BUFFER_USAGE_PIXEL_PACK),
- mStagingTexture(NULL),
- mTextureFormat(DXGI_FORMAT_UNKNOWN),
- mQueuedPackCommand(NULL),
- mDataModified(false)
+ : BufferStorage(renderer, BUFFER_USAGE_PIXEL_PACK), mStagingTexture(), mDataModified(false)
{
}
Buffer11::PackStorage::~PackStorage()
{
- SafeRelease(mStagingTexture);
- SafeDelete(mQueuedPackCommand);
}
-bool Buffer11::PackStorage::copyFromStorage(BufferStorage *source, size_t sourceOffset,
- size_t size, size_t destOffset)
+bool Buffer11::PackStorage::copyFromStorage(BufferStorage *source,
+ size_t sourceOffset,
+ size_t size,
+ size_t destOffset)
{
// We copy through a staging buffer when drawing with a pack buffer,
// or for other cases where we access the pack buffer
@@ -925,7 +1294,7 @@ uint8_t *Buffer11::PackStorage::map(size_t offset, size_t length, GLbitfield acc
gl::Error error = flushQueuedPackCommand();
if (error.isError())
{
- return NULL;
+ return nullptr;
}
mDataModified = (mDataModified || (access & GL_MAP_WRITE_BIT) != 0);
@@ -938,7 +1307,8 @@ void Buffer11::PackStorage::unmap()
// No-op
}
-gl::Error Buffer11::PackStorage::packPixels(ID3D11Texture2D *srcTexure, UINT srcSubresource, const PackPixelsParams &params)
+gl::Error Buffer11::PackStorage::packPixels(const gl::FramebufferAttachment &readAttachment,
+ const PackPixelsParams &params)
{
gl::Error error = flushQueuedPackCommand();
if (error.isError())
@@ -946,54 +1316,37 @@ gl::Error Buffer11::PackStorage::packPixels(ID3D11Texture2D *srcTexure, UINT src
return error;
}
- mQueuedPackCommand = new PackPixelsParams(params);
-
- D3D11_TEXTURE2D_DESC textureDesc;
- srcTexure->GetDesc(&textureDesc);
-
- if (mStagingTexture != NULL &&
- (mTextureFormat != textureDesc.Format ||
- mTextureSize.width != params.area.width ||
- mTextureSize.height != params.area.height))
+ RenderTarget11 *renderTarget = nullptr;
+ error = readAttachment.getRenderTarget(&renderTarget);
+ if (error.isError())
{
- SafeRelease(mStagingTexture);
- mTextureSize.width = 0;
- mTextureSize.height = 0;
- mTextureFormat = DXGI_FORMAT_UNKNOWN;
+ return error;
}
- if (mStagingTexture == NULL)
+ ID3D11Resource *renderTargetResource = renderTarget->getTexture();
+ ASSERT(renderTargetResource);
+
+ unsigned int srcSubresource = renderTarget->getSubresourceIndex();
+ TextureHelper11 srcTexture = TextureHelper11::MakeAndReference(renderTargetResource);
+
+ mQueuedPackCommand.reset(new PackPixelsParams(params));
+
+ gl::Extents srcTextureSize(params.area.width, params.area.height, 1);
+ if (!mStagingTexture.getResource() || mStagingTexture.getFormat() != srcTexture.getFormat() ||
+ mStagingTexture.getExtents() != srcTextureSize)
{
- ID3D11Device *device = mRenderer->getDevice();
- HRESULT hr;
-
- mTextureSize.width = params.area.width;
- mTextureSize.height = params.area.height;
- mTextureFormat = textureDesc.Format;
-
- D3D11_TEXTURE2D_DESC stagingDesc;
- stagingDesc.Width = params.area.width;
- stagingDesc.Height = params.area.height;
- stagingDesc.MipLevels = 1;
- stagingDesc.ArraySize = 1;
- stagingDesc.Format = mTextureFormat;
- stagingDesc.SampleDesc.Count = 1;
- stagingDesc.SampleDesc.Quality = 0;
- stagingDesc.Usage = D3D11_USAGE_STAGING;
- stagingDesc.BindFlags = 0;
- stagingDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
- stagingDesc.MiscFlags = 0;
-
- hr = device->CreateTexture2D(&stagingDesc, NULL, &mStagingTexture);
- if (FAILED(hr))
+ auto textureOrError =
+ CreateStagingTexture(srcTexture.getTextureType(), srcTexture.getFormat(),
+ srcTextureSize, mRenderer->getDevice());
+ if (textureOrError.isError())
{
- ASSERT(hr == E_OUTOFMEMORY);
- return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal staging texture.");
+ return textureOrError.getError();
}
+ mStagingTexture = std::move(textureOrError.getResult());
}
// ReadPixels from multisampled FBOs isn't supported in current GL
- ASSERT(textureDesc.SampleDesc.Count <= 1);
+ ASSERT(srcTexture.getSampleCount() <= 1);
ID3D11DeviceContext *immediateContext = mRenderer->getDeviceContext();
D3D11_BOX srcBox;
@@ -1001,11 +1354,18 @@ gl::Error Buffer11::PackStorage::packPixels(ID3D11Texture2D *srcTexure, UINT src
srcBox.right = params.area.x + params.area.width;
srcBox.top = params.area.y;
srcBox.bottom = params.area.y + params.area.height;
- srcBox.front = 0;
- srcBox.back = 1;
+
+ // Select the correct layer from a 3D attachment
+ srcBox.front = 0;
+ if (mStagingTexture.getTextureType() == GL_TEXTURE_3D)
+ {
+ srcBox.front = static_cast<UINT>(readAttachment.layer());
+ }
+ srcBox.back = srcBox.front + 1;
// Asynchronous copy
- immediateContext->CopySubresourceRegion(mStagingTexture, 0, 0, 0, 0, srcTexure, srcSubresource, &srcBox);
+ immediateContext->CopySubresourceRegion(mStagingTexture.getResource(), 0, 0, 0, 0,
+ srcTexture.getResource(), srcSubresource, &srcBox);
return gl::Error(GL_NO_ERROR);
}
@@ -1016,8 +1376,9 @@ gl::Error Buffer11::PackStorage::flushQueuedPackCommand()
if (mQueuedPackCommand)
{
- gl::Error error = mRenderer->packPixels(mStagingTexture, *mQueuedPackCommand, mMemoryBuffer.data());
- SafeDelete(mQueuedPackCommand);
+ gl::Error error =
+ mRenderer->packPixels(mStagingTexture, *mQueuedPackCommand, mMemoryBuffer.data());
+ mQueuedPackCommand.reset(nullptr);
if (error.isError())
{
return error;
@@ -1029,10 +1390,13 @@ gl::Error Buffer11::PackStorage::flushQueuedPackCommand()
Buffer11::SystemMemoryStorage::SystemMemoryStorage(Renderer11 *renderer)
: Buffer11::BufferStorage(renderer, BUFFER_USAGE_SYSTEM_MEMORY)
-{}
+{
+}
-bool Buffer11::SystemMemoryStorage::copyFromStorage(BufferStorage *source, size_t sourceOffset,
- size_t size, size_t destOffset)
+bool Buffer11::SystemMemoryStorage::copyFromStorage(BufferStorage *source,
+ size_t sourceOffset,
+ size_t size,
+ size_t destOffset)
{
ASSERT(source->isMappable());
const uint8_t *sourceData = source->map(sourceOffset, size, GL_MAP_READ_BIT);
@@ -1066,5 +1430,4 @@ void Buffer11::SystemMemoryStorage::unmap()
{
// No-op
}
-
}
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Buffer11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Buffer11.h
index 39bafe880e..a748db57ae 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Buffer11.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Buffer11.h
@@ -9,12 +9,21 @@
#ifndef LIBANGLE_RENDERER_D3D_D3D11_BUFFER11_H_
#define LIBANGLE_RENDERER_D3D_D3D11_BUFFER11_H_
+#include <map>
+
#include "libANGLE/angletypes.h"
#include "libANGLE/renderer/d3d/BufferD3D.h"
+namespace gl
+{
+class FramebufferAttachment;
+}
+
namespace rx
{
class Renderer11;
+struct SourceIndexData;
+struct TranslatedAttribute;
enum BufferUsage
{
@@ -25,6 +34,9 @@ enum BufferUsage
BUFFER_USAGE_PIXEL_PACK,
BUFFER_USAGE_UNIFORM,
BUFFER_USAGE_SYSTEM_MEMORY,
+ BUFFER_USAGE_EMULATED_INDEXED_VERTEX,
+
+ BUFFER_USAGE_COUNT,
};
struct PackPixelsParams
@@ -50,28 +62,32 @@ class Buffer11 : public BufferD3D
Buffer11(Renderer11 *renderer);
virtual ~Buffer11();
- static Buffer11 *makeBuffer11(BufferImpl *buffer);
-
ID3D11Buffer *getBuffer(BufferUsage usage);
+ ID3D11Buffer *getEmulatedIndexedBuffer(SourceIndexData *indexInfo, const TranslatedAttribute *attribute);
+ ID3D11Buffer *getConstantBufferRange(GLintptr offset, GLsizeiptr size);
ID3D11ShaderResourceView *getSRV(DXGI_FORMAT srvFormat);
bool isMapped() const { return mMappedStorage != NULL; }
- gl::Error packPixels(ID3D11Texture2D *srcTexure, UINT srcSubresource, const PackPixelsParams &params);
+ gl::Error packPixels(const gl::FramebufferAttachment &readAttachment,
+ const PackPixelsParams &params);
+ size_t getTotalCPUBufferMemoryBytes() const;
// BufferD3D implementation
virtual size_t getSize() const { return mSize; }
virtual bool supportsDirectBinding() const;
+ gl::Error getData(const uint8_t **outData) override;
// BufferImpl implementation
virtual gl::Error setData(const void* data, size_t size, GLenum usage);
- gl::Error getData(const uint8_t **outData) override;
virtual gl::Error setSubData(const void* data, size_t size, size_t offset);
virtual gl::Error copySubData(BufferImpl* source, GLintptr sourceOffset, GLintptr destOffset, GLsizeiptr size);
- virtual gl::Error map(size_t offset, size_t length, GLbitfield access, GLvoid **mapPtr);
- virtual gl::Error unmap();
+ virtual gl::Error map(GLenum access, GLvoid **mapPtr);
+ virtual gl::Error mapRange(size_t offset, size_t length, GLbitfield access, GLvoid **mapPtr);
+ virtual gl::Error unmap(GLboolean *result);
virtual void markTransformFeedbackUsage();
private:
class BufferStorage;
+ class EmulatedIndexedStorage;
class NativeStorage;
class PackStorage;
class SystemMemoryStorage;
@@ -81,21 +97,41 @@ class Buffer11 : public BufferD3D
BufferStorage *mMappedStorage;
- std::map<BufferUsage, BufferStorage*> mBufferStorages;
+ std::vector<BufferStorage*> mBufferStorages;
+
+ struct ConstantBufferCacheEntry
+ {
+ ConstantBufferCacheEntry() : storage(nullptr), lruCount(0) { }
+
+ BufferStorage *storage;
+ unsigned int lruCount;
+ };
+
+ // Cache of D3D11 constant buffer for specific ranges of buffer data.
+ // This is used to emulate UBO ranges on 11.0 devices.
+ // Constant buffers are indexed by there start offset.
+ typedef std::map<GLintptr /*offset*/, ConstantBufferCacheEntry> ConstantBufferCache;
+ ConstantBufferCache mConstantBufferRangeStoragesCache;
+ size_t mConstantBufferStorageAdditionalSize;
+ unsigned int mMaxConstantBufferLruCount;
typedef std::pair<ID3D11Buffer *, ID3D11ShaderResourceView *> BufferSRVPair;
std::map<DXGI_FORMAT, BufferSRVPair> mBufferResourceViews;
unsigned int mReadUsageCount;
- bool mHasSystemMemoryStorage;
void markBufferUsage();
NativeStorage *getStagingStorage();
PackStorage *getPackStorage();
gl::Error getSystemMemoryStorage(SystemMemoryStorage **storageOut);
+ void updateBufferStorage(BufferStorage *storage, size_t sourceOffset, size_t storageSize);
BufferStorage *getBufferStorage(BufferUsage usage);
BufferStorage *getLatestBufferStorage() const;
+
+ BufferStorage *getConstantBufferRangeStorage(GLintptr offset, GLsizeiptr size);
+
+ void invalidateEmulatedIndexedBuffer();
};
}
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Clear11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Clear11.cpp
index 057c3bed42..cd95c65d1c 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Clear11.cpp
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Clear11.cpp
@@ -17,6 +17,7 @@
#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h"
#include "libANGLE/renderer/d3d/d3d11/RenderTarget11.h"
#include "libANGLE/renderer/d3d/d3d11/formatutils11.h"
+#include "third_party/trace_event/trace_event.h"
// Precompiled shaders
#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearfloat11vs.h"
@@ -44,7 +45,7 @@ static void ApplyVertices(const gl::Extents &framebufferSize, const gl::Rectangl
float bottom = 1.0f;
// Clip the quad coordinates to the scissor if needed
- if (scissor != NULL)
+ if (scissor != nullptr)
{
left = std::max(left, (scissor->x / float(framebufferSize.width)) * 2.0f - 1.0f);
right = std::min(right, ((scissor->x + scissor->width) / float(framebufferSize.width)) * 2.0f - 1.0f);
@@ -58,35 +59,46 @@ static void ApplyVertices(const gl::Extents &framebufferSize, const gl::Rectangl
d3d11::SetPositionDepthColorVertex<T>(vertices + 3, right, top, depthClear, color);
}
-template <unsigned int vsSize, unsigned int psSize>
-Clear11::ClearShader Clear11::CreateClearShader(ID3D11Device *device, DXGI_FORMAT colorType, const BYTE (&vsByteCode)[vsSize], const BYTE (&psByteCode)[psSize])
+Clear11::ClearShader::ClearShader(DXGI_FORMAT colorType,
+ const char *inputLayoutName,
+ const BYTE *vsByteCode,
+ size_t vsSize,
+ const char *vsDebugName,
+ const BYTE *psByteCode,
+ size_t psSize,
+ const char *psDebugName)
+ : inputLayout(nullptr),
+ vertexShader(vsByteCode, vsSize, vsDebugName),
+ pixelShader(psByteCode, psSize, psDebugName)
{
- HRESULT result;
-
- ClearShader shader = { 0 };
-
D3D11_INPUT_ELEMENT_DESC quadLayout[] =
{
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "COLOR", 0, colorType, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
};
- result = device->CreateInputLayout(quadLayout, ArraySize(quadLayout), vsByteCode, vsSize, &shader.inputLayout);
- ASSERT(SUCCEEDED(result));
-
- result = device->CreateVertexShader(vsByteCode, vsSize, NULL, &shader.vertexShader);
- ASSERT(SUCCEEDED(result));
-
- result = device->CreatePixelShader(psByteCode, psSize, NULL, &shader.pixelShader);
- ASSERT(SUCCEEDED(result));
+ inputLayout = new d3d11::LazyInputLayout(quadLayout, 2, vsByteCode, vsSize, inputLayoutName);
+}
- return shader;
+Clear11::ClearShader::~ClearShader()
+{
+ SafeDelete(inputLayout);
+ vertexShader.release();
+ pixelShader.release();
}
Clear11::Clear11(Renderer11 *renderer)
- : mRenderer(renderer), mClearBlendStates(StructLessThan<ClearBlendInfo>), mClearDepthStencilStates(StructLessThan<ClearDepthStencilInfo>),
- mVertexBuffer(NULL), mRasterizerState(NULL), mSupportsClearView(false)
+ : mRenderer(renderer),
+ mClearBlendStates(StructLessThan<ClearBlendInfo>),
+ mFloatClearShader(nullptr),
+ mUintClearShader(nullptr),
+ mIntClearShader(nullptr),
+ mClearDepthStencilStates(StructLessThan<ClearDepthStencilInfo>),
+ mVertexBuffer(nullptr),
+ mRasterizerState(nullptr)
{
+ TRACE_EVENT0("gpu.angle", "Clear11::Clear11");
+
HRESULT result;
ID3D11Device *device = renderer->getDevice();
@@ -98,7 +110,7 @@ Clear11::Clear11(Renderer11 *renderer)
vbDesc.MiscFlags = 0;
vbDesc.StructureByteStride = 0;
- result = device->CreateBuffer(&vbDesc, NULL, &mVertexBuffer);
+ result = device->CreateBuffer(&vbDesc, nullptr, &mVertexBuffer);
ASSERT(SUCCEEDED(result));
d3d11::SetDebugName(mVertexBuffer, "Clear11 masked clear vertex buffer");
@@ -118,29 +130,48 @@ Clear11::Clear11(Renderer11 *renderer)
ASSERT(SUCCEEDED(result));
d3d11::SetDebugName(mRasterizerState, "Clear11 masked clear rasterizer state");
- if (renderer->getFeatureLevel() <= D3D_FEATURE_LEVEL_9_3)
+ if (mRenderer->getRenderer11DeviceCaps().featureLevel <= D3D_FEATURE_LEVEL_9_3)
{
- mFloatClearShader = CreateClearShader(device, DXGI_FORMAT_R32G32B32A32_FLOAT, g_VS_ClearFloat, g_PS_ClearFloat_FL9);
+ mFloatClearShader = new ClearShader(DXGI_FORMAT_R32G32B32A32_FLOAT,
+ "Clear11 Float IL",
+ g_VS_ClearFloat,
+ ArraySize(g_VS_ClearFloat),
+ "Clear11 Float VS",
+ g_PS_ClearFloat_FL9,
+ ArraySize(g_PS_ClearFloat_FL9),
+ "Clear11 Float PS");
}
else
{
- mFloatClearShader = CreateClearShader(device, DXGI_FORMAT_R32G32B32A32_FLOAT, g_VS_ClearFloat, g_PS_ClearFloat);
+ mFloatClearShader = new ClearShader(DXGI_FORMAT_R32G32B32A32_FLOAT,
+ "Clear11 Float IL",
+ g_VS_ClearFloat,
+ ArraySize(g_VS_ClearFloat),
+ "Clear11 Float VS",
+ g_PS_ClearFloat,
+ ArraySize(g_PS_ClearFloat),
+ "Clear11 Float PS");
}
if (renderer->isES3Capable())
{
- mUintClearShader = CreateClearShader(device, DXGI_FORMAT_R32G32B32A32_UINT, g_VS_ClearUint, g_PS_ClearUint );
- mIntClearShader = CreateClearShader(device, DXGI_FORMAT_R32G32B32A32_SINT, g_VS_ClearSint, g_PS_ClearSint );
- }
-
-#if defined(ANGLE_ENABLE_D3D11_1)
- if (renderer->getDeviceContext1IfSupported())
- {
- D3D11_FEATURE_DATA_D3D11_OPTIONS d3d11Options;
- device->CheckFeatureSupport(D3D11_FEATURE_D3D11_OPTIONS, &d3d11Options, sizeof(D3D11_FEATURE_DATA_D3D11_OPTIONS));
- mSupportsClearView = (d3d11Options.ClearView != FALSE);
+ mUintClearShader = new ClearShader(DXGI_FORMAT_R32G32B32A32_UINT,
+ "Clear11 UINT IL",
+ g_VS_ClearUint,
+ ArraySize(g_VS_ClearUint),
+ "Clear11 UINT VS",
+ g_PS_ClearUint,
+ ArraySize(g_PS_ClearUint),
+ "Clear11 UINT PS");
+ mIntClearShader = new ClearShader(DXGI_FORMAT_R32G32B32A32_UINT,
+ "Clear11 SINT IL",
+ g_VS_ClearSint,
+ ArraySize(g_VS_ClearSint),
+ "Clear11 SINT VS",
+ g_PS_ClearSint,
+ ArraySize(g_PS_ClearSint),
+ "Clear11 SINT PS");
}
-#endif
}
Clear11::~Clear11()
@@ -151,20 +182,9 @@ Clear11::~Clear11()
}
mClearBlendStates.clear();
- SafeRelease(mFloatClearShader.inputLayout);
- SafeRelease(mFloatClearShader.vertexShader);
- SafeRelease(mFloatClearShader.pixelShader);
-
- if (mRenderer->isES3Capable())
- {
- SafeRelease(mUintClearShader.inputLayout);
- SafeRelease(mUintClearShader.vertexShader);
- SafeRelease(mUintClearShader.pixelShader);
-
- SafeRelease(mIntClearShader.inputLayout);
- SafeRelease(mIntClearShader.vertexShader);
- SafeRelease(mIntClearShader.pixelShader);
- }
+ SafeDelete(mFloatClearShader);
+ SafeDelete(mUintClearShader);
+ SafeDelete(mIntClearShader);
for (ClearDepthStencilStateMap::iterator i = mClearDepthStencilStates.begin(); i != mClearDepthStencilStates.end(); i++)
{
@@ -178,10 +198,10 @@ Clear11::~Clear11()
gl::Error Clear11::clearFramebuffer(const ClearParameters &clearParams, const gl::Framebuffer::Data &fboData)
{
- const auto &colorAttachments = fboData.mColorAttachments;
- const auto &drawBufferStates = fboData.mDrawBufferStates;
- const auto *depthAttachment = fboData.mDepthAttachment;
- const auto *stencilAttachment = fboData.mStencilAttachment;
+ const auto &colorAttachments = fboData.getColorAttachments();
+ const auto &drawBufferStates = fboData.getDrawBufferStates();
+ const auto *depthAttachment = fboData.getDepthAttachment();
+ const auto *stencilAttachment = fboData.getStencilAttachment();
ASSERT(colorAttachments.size() == drawBufferStates.size());
@@ -206,24 +226,18 @@ gl::Error Clear11::clearFramebuffer(const ClearParameters &clearParams, const gl
gl::Extents framebufferSize;
- auto iter = std::find_if(colorAttachments.begin(), colorAttachments.end(), [](const gl::FramebufferAttachment *attachment) { return attachment != nullptr; });
- if (iter != colorAttachments.end())
+ const gl::FramebufferAttachment *colorAttachment = fboData.getFirstColorAttachment();
+ if (colorAttachment != nullptr)
{
- framebufferSize.width = (*iter)->getWidth();
- framebufferSize.height = (*iter)->getHeight();
- framebufferSize.depth = 1;
+ framebufferSize = colorAttachment->getSize();
}
else if (depthAttachment != nullptr)
{
- framebufferSize.width = depthAttachment->getWidth();
- framebufferSize.height = depthAttachment->getHeight();
- framebufferSize.depth = 1;
+ framebufferSize = depthAttachment->getSize();
}
else if (stencilAttachment != nullptr)
{
- framebufferSize.width = stencilAttachment->getWidth();
- framebufferSize.height = stencilAttachment->getHeight();
- framebufferSize.depth = 1;
+ framebufferSize = stencilAttachment->getSize();
}
else
{
@@ -245,34 +259,40 @@ gl::Error Clear11::clearFramebuffer(const ClearParameters &clearParams, const gl
clearParams.scissor.y + clearParams.scissor.height < framebufferSize.height);
std::vector<MaskedRenderTarget> maskedClearRenderTargets;
- RenderTarget11* maskedClearDepthStencil = NULL;
+ RenderTarget11* maskedClearDepthStencil = nullptr;
ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
+#if defined(ANGLE_ENABLE_D3D11_1)
ID3D11DeviceContext1 *deviceContext1 = mRenderer->getDeviceContext1IfSupported();
+#endif
+ ID3D11Device *device = mRenderer->getDevice();
- for (size_t colorAttachment = 0; colorAttachment < colorAttachments.size(); colorAttachment++)
+ for (size_t colorAttachmentIndex = 0; colorAttachmentIndex < colorAttachments.size();
+ colorAttachmentIndex++)
{
- if (clearParams.clearColor[colorAttachment] &&
- colorAttachments[colorAttachment] != nullptr &&
- drawBufferStates[colorAttachment] != GL_NONE)
- {
- const gl::FramebufferAttachment *attachment = colorAttachments[colorAttachment];
+ const gl::FramebufferAttachment &attachment = colorAttachments[colorAttachmentIndex];
- RenderTarget11 *renderTarget = NULL;
- gl::Error error = d3d11::GetAttachmentRenderTarget(attachment, &renderTarget);
+ if (clearParams.clearColor[colorAttachmentIndex] && attachment.isAttached() &&
+ drawBufferStates[colorAttachmentIndex] != GL_NONE)
+ {
+ RenderTarget11 *renderTarget = nullptr;
+ gl::Error error = attachment.getRenderTarget(&renderTarget);
if (error.isError())
{
return error;
}
- const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(attachment->getInternalFormat());
+ const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(attachment.getInternalFormat());
if (clearParams.colorClearType == GL_FLOAT &&
!(formatInfo.componentType == GL_FLOAT || formatInfo.componentType == GL_UNSIGNED_NORMALIZED || formatInfo.componentType == GL_SIGNED_NORMALIZED))
{
- ERR("It is undefined behaviour to clear a render buffer which is not normalized fixed point or floating-"
- "point to floating point values (color attachment %u has internal format 0x%X).", colorAttachment,
- attachment->getInternalFormat());
+ ERR(
+ "It is undefined behaviour to clear a render buffer which is not normalized "
+ "fixed point or floating-"
+ "point to floating point values (color attachment %u has internal format "
+ "0x%X).",
+ colorAttachmentIndex, attachment.getInternalFormat());
}
if ((formatInfo.redBits == 0 || !clearParams.colorMaskRed) &&
@@ -283,7 +303,7 @@ gl::Error Clear11::clearFramebuffer(const ClearParameters &clearParams, const gl
// Every channel either does not exist in the render target or is masked out
continue;
}
- else if ((!mSupportsClearView && needScissoredClear) || clearParams.colorClearType != GL_FLOAT ||
+ else if ((!(mRenderer->getRenderer11DeviceCaps().supportsClearView) && needScissoredClear) || clearParams.colorClearType != GL_FLOAT ||
(formatInfo.redBits > 0 && !clearParams.colorMaskRed) ||
(formatInfo.greenBits > 0 && !clearParams.colorMaskGreen) ||
(formatInfo.blueBits > 0 && !clearParams.colorMaskBlue) ||
@@ -291,7 +311,7 @@ gl::Error Clear11::clearFramebuffer(const ClearParameters &clearParams, const gl
{
// A masked clear is required, or a scissored clear is required and ID3D11DeviceContext1::ClearView is unavailable
MaskedRenderTarget maskAndRt;
- bool clearColor = clearParams.clearColor[colorAttachment];
+ bool clearColor = clearParams.clearColor[colorAttachmentIndex];
maskAndRt.colorMask[0] = (clearColor && clearParams.colorMaskRed);
maskAndRt.colorMask[1] = (clearColor && clearParams.colorMaskGreen);
maskAndRt.colorMask[2] = (clearColor && clearParams.colorMaskBlue);
@@ -313,7 +333,7 @@ gl::Error Clear11::clearFramebuffer(const ClearParameters &clearParams, const gl
// Check if the actual format has a channel that the internal format does not and set them to the
// default values
- const float clearValues[4] =
+ float clearValues[4] =
{
((formatInfo.redBits == 0 && dxgiFormatInfo.redBits > 0) ? 0.0f : clearParams.colorFClearValue.red),
((formatInfo.greenBits == 0 && dxgiFormatInfo.greenBits > 0) ? 0.0f : clearParams.colorFClearValue.green),
@@ -321,9 +341,17 @@ gl::Error Clear11::clearFramebuffer(const ClearParameters &clearParams, const gl
((formatInfo.alphaBits == 0 && dxgiFormatInfo.alphaBits > 0) ? 1.0f : clearParams.colorFClearValue.alpha),
};
- if (needScissoredClear)
+ if (dxgiFormatInfo.alphaBits == 1)
{
+ // Some drivers do not correctly handle calling Clear() on a format with 1-bit alpha.
+ // They can incorrectly round all non-zero values up to 1.0f. Note that WARP does not do this.
+ // We should handle the rounding for them instead.
+ clearValues[3] = (clearParams.colorFClearValue.alpha >= 0.5f) ? 1.0f : 0.0f;
+ }
+
#if defined(ANGLE_ENABLE_D3D11_1)
+ if (needScissoredClear)
+ {
// We shouldn't reach here if deviceContext1 is unavailable.
ASSERT(deviceContext1);
@@ -334,9 +362,9 @@ gl::Error Clear11::clearFramebuffer(const ClearParameters &clearParams, const gl
rect.bottom = clearParams.scissor.y + clearParams.scissor.height;
deviceContext1->ClearView(framebufferRTV, clearValues, &rect, 1);
-#endif
}
else
+#endif
{
deviceContext->ClearRenderTargetView(framebufferRTV, clearValues);
}
@@ -349,8 +377,8 @@ gl::Error Clear11::clearFramebuffer(const ClearParameters &clearParams, const gl
const gl::FramebufferAttachment *attachment = (depthAttachment != nullptr) ? depthAttachment : stencilAttachment;
ASSERT(attachment != nullptr);
- RenderTarget11 *renderTarget = NULL;
- gl::Error error = d3d11::GetAttachmentRenderTarget(attachment, &renderTarget);
+ RenderTarget11 *renderTarget = nullptr;
+ gl::Error error = attachment->getRenderTarget(&renderTarget);
if (error.isError())
{
return error;
@@ -421,7 +449,7 @@ gl::Error Clear11::clearFramebuffer(const ClearParameters &clearParams, const gl
rtvs[i] = rtv;
}
- ID3D11DepthStencilView *dsv = maskedClearDepthStencil ? maskedClearDepthStencil->getDepthStencilView() : NULL;
+ ID3D11DepthStencilView *dsv = maskedClearDepthStencil ? maskedClearDepthStencil->getDepthStencilView() : nullptr;
ID3D11BlendState *blendState = getBlendState(maskedClearRenderTargets);
const FLOAT blendFactors[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
@@ -433,7 +461,7 @@ gl::Error Clear11::clearFramebuffer(const ClearParameters &clearParams, const gl
// Set the vertices
UINT vertexStride = 0;
const UINT startIdx = 0;
- const ClearShader* shader = NULL;
+ ClearShader *shader = nullptr;
D3D11_MAPPED_SUBRESOURCE mappedResource;
HRESULT result = deviceContext->Map(mVertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
if (FAILED(result))
@@ -441,25 +469,25 @@ gl::Error Clear11::clearFramebuffer(const ClearParameters &clearParams, const gl
return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal masked clear vertex buffer, HRESULT: 0x%X.", result);
}
- const gl::Rectangle *scissorPtr = clearParams.scissorEnabled ? &clearParams.scissor : NULL;
+ const gl::Rectangle *scissorPtr = clearParams.scissorEnabled ? &clearParams.scissor : nullptr;
switch (clearParams.colorClearType)
{
case GL_FLOAT:
ApplyVertices(framebufferSize, scissorPtr, clearParams.colorFClearValue, clearParams.depthClearValue, mappedResource.pData);
vertexStride = sizeof(d3d11::PositionDepthColorVertex<float>);
- shader = &mFloatClearShader;
+ shader = mFloatClearShader;
break;
case GL_UNSIGNED_INT:
ApplyVertices(framebufferSize, scissorPtr, clearParams.colorUIClearValue, clearParams.depthClearValue, mappedResource.pData);
vertexStride = sizeof(d3d11::PositionDepthColorVertex<unsigned int>);
- shader = &mUintClearShader;
+ shader = mUintClearShader;
break;
case GL_INT:
ApplyVertices(framebufferSize, scissorPtr, clearParams.colorIClearValue, clearParams.depthClearValue, mappedResource.pData);
vertexStride = sizeof(d3d11::PositionDepthColorVertex<int>);
- shader = &mIntClearShader;
+ shader = mIntClearShader;
break;
default:
@@ -473,8 +501,8 @@ gl::Error Clear11::clearFramebuffer(const ClearParameters &clearParams, const gl
D3D11_VIEWPORT viewport;
viewport.TopLeftX = 0;
viewport.TopLeftY = 0;
- viewport.Width = framebufferSize.width;
- viewport.Height = framebufferSize.height;
+ viewport.Width = static_cast<FLOAT>(framebufferSize.width);
+ viewport.Height = static_cast<FLOAT>(framebufferSize.height);
viewport.MinDepth = 0;
viewport.MaxDepth = 1;
deviceContext->RSSetViewports(1, &viewport);
@@ -485,17 +513,18 @@ gl::Error Clear11::clearFramebuffer(const ClearParameters &clearParams, const gl
deviceContext->RSSetState(mRasterizerState);
// Apply shaders
- deviceContext->IASetInputLayout(shader->inputLayout);
- deviceContext->VSSetShader(shader->vertexShader, NULL, 0);
- deviceContext->PSSetShader(shader->pixelShader, NULL, 0);
- deviceContext->GSSetShader(NULL, NULL, 0);
+ deviceContext->IASetInputLayout(shader->inputLayout->resolve(device));
+ deviceContext->VSSetShader(shader->vertexShader.resolve(device), nullptr, 0);
+ deviceContext->PSSetShader(shader->pixelShader.resolve(device), nullptr, 0);
+ deviceContext->GSSetShader(nullptr, nullptr, 0);
// Apply vertex buffer
deviceContext->IASetVertexBuffers(0, 1, &mVertexBuffer, &vertexStride, &startIdx);
deviceContext->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
// Apply render targets
- deviceContext->OMSetRenderTargets(rtvs.size(), (rtvs.empty() ? NULL : &rtvs[0]), dsv);
+ deviceContext->OMSetRenderTargets(static_cast<unsigned int>(rtvs.size()),
+ (rtvs.empty() ? nullptr : &rtvs[0]), dsv);
// Draw the clear quad
deviceContext->Draw(4, 0);
@@ -509,7 +538,7 @@ gl::Error Clear11::clearFramebuffer(const ClearParameters &clearParams, const gl
ID3D11BlendState *Clear11::getBlendState(const std::vector<MaskedRenderTarget>& rts)
{
- ClearBlendInfo blendKey = { 0 };
+ ClearBlendInfo blendKey = {};
for (unsigned int i = 0; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; i++)
{
if (i < rts.size())
@@ -552,12 +581,12 @@ ID3D11BlendState *Clear11::getBlendState(const std::vector<MaskedRenderTarget>&
}
ID3D11Device *device = mRenderer->getDevice();
- ID3D11BlendState* blendState = NULL;
+ ID3D11BlendState* blendState = nullptr;
HRESULT result = device->CreateBlendState(&blendDesc, &blendState);
if (FAILED(result) || !blendState)
{
ERR("Unable to create a ID3D11BlendState, HRESULT: 0x%X.", result);
- return NULL;
+ return nullptr;
}
mClearBlendStates[blendKey] = blendState;
@@ -597,12 +626,12 @@ ID3D11DepthStencilState *Clear11::getDepthStencilState(const ClearParameters &cl
dsDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
ID3D11Device *device = mRenderer->getDevice();
- ID3D11DepthStencilState* dsState = NULL;
+ ID3D11DepthStencilState* dsState = nullptr;
HRESULT result = device->CreateDepthStencilState(&dsDesc, &dsState);
if (FAILED(result) || !dsState)
{
ERR("Unable to create a ID3D11DepthStencilState, HRESULT: 0x%X.", result);
- return NULL;
+ return nullptr;
}
mClearDepthStencilStates[dsKey] = dsState;
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Clear11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Clear11.h
index 4797ca1aa0..3ff73c85d1 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Clear11.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Clear11.h
@@ -15,6 +15,7 @@
#include "libANGLE/angletypes.h"
#include "libANGLE/Error.h"
#include "libANGLE/Framebuffer.h"
+#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h"
namespace rx
{
@@ -41,29 +42,32 @@ class Clear11 : angle::NonCopyable
ID3D11BlendState *getBlendState(const std::vector<MaskedRenderTarget> &rts);
ID3D11DepthStencilState *getDepthStencilState(const ClearParameters &clearParams);
- struct ClearShader
+ struct ClearShader final : public angle::NonCopyable
{
- ID3D11InputLayout *inputLayout;
- ID3D11VertexShader *vertexShader;
- ID3D11PixelShader *pixelShader;
+ ClearShader(DXGI_FORMAT colorType,
+ const char *inputLayoutName,
+ const BYTE *vsByteCode,
+ size_t vsSize,
+ const char *vsDebugName,
+ const BYTE *psByteCode,
+ size_t psSize,
+ const char *psDebugName);
+ ~ClearShader();
+
+ d3d11::LazyInputLayout *inputLayout;
+ d3d11::LazyShader<ID3D11VertexShader> vertexShader;
+ d3d11::LazyShader<ID3D11PixelShader> pixelShader;
};
template <unsigned int vsSize, unsigned int psSize>
static ClearShader CreateClearShader(ID3D11Device *device, DXGI_FORMAT colorType, const BYTE(&vsByteCode)[vsSize], const BYTE(&psByteCode)[psSize]);
- Renderer11 *mRenderer;
-
struct ClearBlendInfo
{
bool maskChannels[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT][4];
};
typedef bool(*ClearBlendInfoComparisonFunction)(const ClearBlendInfo&, const ClearBlendInfo &);
typedef std::map<ClearBlendInfo, ID3D11BlendState*, ClearBlendInfoComparisonFunction> ClearBlendStateMap;
- ClearBlendStateMap mClearBlendStates;
-
- ClearShader mFloatClearShader;
- ClearShader mUintClearShader;
- ClearShader mIntClearShader;
struct ClearDepthStencilInfo
{
@@ -71,14 +75,21 @@ class Clear11 : angle::NonCopyable
bool clearStencil;
UINT8 stencilWriteMask;
};
- typedef bool (*ClearDepthStencilInfoComparisonFunction)(const ClearDepthStencilInfo&, const ClearDepthStencilInfo &);
+ typedef bool(*ClearDepthStencilInfoComparisonFunction)(const ClearDepthStencilInfo&, const ClearDepthStencilInfo &);
typedef std::map<ClearDepthStencilInfo, ID3D11DepthStencilState*, ClearDepthStencilInfoComparisonFunction> ClearDepthStencilStateMap;
+
+ Renderer11 *mRenderer;
+
+ ClearBlendStateMap mClearBlendStates;
+
+ ClearShader *mFloatClearShader;
+ ClearShader *mUintClearShader;
+ ClearShader *mIntClearShader;
+
ClearDepthStencilStateMap mClearDepthStencilStates;
ID3D11Buffer *mVertexBuffer;
ID3D11RasterizerState *mRasterizerState;
-
- bool mSupportsClearView;
};
}
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/DebugAnnotator11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/DebugAnnotator11.cpp
index f1fe2bb2c7..1c35ab45cc 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/DebugAnnotator11.cpp
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/DebugAnnotator11.cpp
@@ -37,50 +37,90 @@ DebugAnnotator11::~DebugAnnotator11()
}
}
-void DebugAnnotator11::beginEvent(const std::wstring &eventName)
+void DebugAnnotator11::beginEvent(const wchar_t *eventName)
{
initializeDevice();
+ if (mUserDefinedAnnotation != nullptr)
+ {
#if defined(ANGLE_ENABLE_D3D11_1)
- mUserDefinedAnnotation->BeginEvent(eventName.c_str());
+ mUserDefinedAnnotation->BeginEvent(eventName);
#endif
+ }
}
void DebugAnnotator11::endEvent()
{
initializeDevice();
+ if (mUserDefinedAnnotation != nullptr)
+ {
#if defined(ANGLE_ENABLE_D3D11_1)
- mUserDefinedAnnotation->EndEvent();
+ mUserDefinedAnnotation->EndEvent();
#endif
+ }
}
-void DebugAnnotator11::setMarker(const std::wstring &markerName)
+void DebugAnnotator11::setMarker(const wchar_t *markerName)
{
initializeDevice();
+ if (mUserDefinedAnnotation != nullptr)
+ {
#if defined(ANGLE_ENABLE_D3D11_1)
- mUserDefinedAnnotation->SetMarker(markerName.c_str());
+ mUserDefinedAnnotation->SetMarker(markerName);
#endif
+ }
}
bool DebugAnnotator11::getStatus()
{
- // ID3DUserDefinedAnnotation::GetStatus doesn't work with the Graphics Diagnostics tools in Visual Studio 2013.
+#if defined(ANGLE_ENABLE_WINDOWS_STORE)
+#if (NTDDI_VERSION == NTDDI_WIN10)
+ initializeDevice();
+
+ if (mUserDefinedAnnotation != nullptr)
+ {
+ return !!(mUserDefinedAnnotation->GetStatus());
+ }
+
+ return true; // Default if initializeDevice() failed
+#elif defined(_DEBUG) && (WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP)
+ static bool underCapture = true;
-#if defined(_DEBUG) && defined(ANGLE_ENABLE_WINDOWS_STORE) && (WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP)
- // In the Windows Store, we can use IDXGraphicsAnalysis. The call to GetDebugInterface1 only succeeds if the app is under capture.
+ // ID3DUserDefinedAnnotation::GetStatus doesn't work with the Graphics Diagnostics tools in
+ // Windows 8.1/Visual Studio 2013. We can use IDXGraphicsAnalysis, though.
+ // The call to GetDebugInterface1 only succeeds if the app is under capture.
// This should only be called in DEBUG mode.
- // If an app links against DXGIGetDebugInterface1 in release mode then it will fail Windows Store ingestion checks.
- IDXGraphicsAnalysis *graphicsAnalysis;
- DXGIGetDebugInterface1(0, IID_PPV_ARGS(&graphicsAnalysis));
- bool underCapture = (graphicsAnalysis != nullptr);
- SafeRelease(graphicsAnalysis);
- return underCapture;
-#endif // _DEBUG && !ANGLE_ENABLE_WINDOWS_STORE
+ // If an app links against DXGIGetDebugInterface1 in release mode then it will fail Windows
+ // Store ingestion checks.
+
+ // Cache the result to reduce the number of calls to DXGIGetDebugInterface1
+ static bool triedIDXGraphicsAnalysis = false;
+
+ if (!triedIDXGraphicsAnalysis)
+ {
+ IDXGraphicsAnalysis *graphicsAnalysis = nullptr;
+
+ HRESULT result = DXGIGetDebugInterface1(0, IID_PPV_ARGS(&graphicsAnalysis));
+ if (SUCCEEDED(result))
+ {
+ underCapture = (graphicsAnalysis != nullptr);
+ }
- // Otherwise, we have to return true here.
+ SafeRelease(graphicsAnalysis);
+ triedIDXGraphicsAnalysis = true;
+ }
+
+ return underCapture;
+#else
+ // We can't detect GetStatus() on release WinRT 8.1 builds, so always return true.
+ return true;
+#endif // (NTDDI_VERSION == NTDDI_WIN10) or _DEBUG
+#else
+ // We can't detect GetStatus() on desktop ANGLE builds so always return true.
return true;
+#endif // ANGLE_ENABLE_WINDOWS_STORE
}
void DebugAnnotator11::initializeDevice()
@@ -103,16 +143,17 @@ void DebugAnnotator11::initializeDevice()
// Create a D3D_DRIVER_TYPE_NULL device, which is much cheaper than other types of device.
hr = D3D11CreateDevice(NULL, D3D_DRIVER_TYPE_NULL, nullptr, 0, nullptr, 0, D3D11_SDK_VERSION, &device, nullptr, &context);
ASSERT(SUCCEEDED(hr));
-
+ if (SUCCEEDED(hr))
+ {
#if defined(ANGLE_ENABLE_D3D11_1)
- mUserDefinedAnnotation = d3d11::DynamicCastComObject<ID3DUserDefinedAnnotation>(context);
- ASSERT(mUserDefinedAnnotation != nullptr);
+ mUserDefinedAnnotation = d3d11::DynamicCastComObject<ID3DUserDefinedAnnotation>(context);
+ ASSERT(mUserDefinedAnnotation != nullptr);
#endif
+ mInitialized = true;
+ }
SafeRelease(device);
SafeRelease(context);
-
- mInitialized = true;
}
}
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/DebugAnnotator11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/DebugAnnotator11.h
index 3df62b015c..d1a0f7fd2e 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/DebugAnnotator11.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/DebugAnnotator11.h
@@ -21,9 +21,9 @@ class DebugAnnotator11 : public gl::DebugAnnotator
public:
DebugAnnotator11();
~DebugAnnotator11() override;
- void beginEvent(const std::wstring &eventName) override;
+ void beginEvent(const wchar_t *eventName) override;
void endEvent() override;
- void setMarker(const std::wstring &markerName) override;
+ void setMarker(const wchar_t *markerName) override;
bool getStatus() override;
private:
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Fence11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Fence11.cpp
index 8552bc2beb..53fac65f2a 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Fence11.cpp
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Fence11.cpp
@@ -76,23 +76,22 @@ FenceNV11::~FenceNV11()
SafeRelease(mQuery);
}
-gl::Error FenceNV11::set()
+gl::Error FenceNV11::set(GLenum condition)
{
return FenceSetHelper(this);
}
-gl::Error FenceNV11::test(bool flushCommandBuffer, GLboolean *outFinished)
+gl::Error FenceNV11::test(GLboolean *outFinished)
{
- return FenceTestHelper(this, flushCommandBuffer, outFinished);
+ return FenceTestHelper(this, true, outFinished);
}
-gl::Error FenceNV11::finishFence(GLboolean *outFinished)
+gl::Error FenceNV11::finish()
{
- ASSERT(outFinished);
-
- while (*outFinished != GL_TRUE)
+ GLboolean finished = GL_FALSE;
+ while (finished != GL_TRUE)
{
- gl::Error error = test(true, outFinished);
+ gl::Error error = FenceTestHelper(this, true, &finished);
if (error.isError())
{
return error;
@@ -124,7 +123,7 @@ FenceSync11::FenceSync11(Renderer11 *renderer)
mRenderer(renderer),
mQuery(NULL)
{
- LARGE_INTEGER counterFreqency = { 0 };
+ LARGE_INTEGER counterFreqency = {};
BOOL success = QueryPerformanceFrequency(&counterFreqency);
UNUSED_ASSERTION_VARIABLE(success);
ASSERT(success);
@@ -137,8 +136,9 @@ FenceSync11::~FenceSync11()
SafeRelease(mQuery);
}
-gl::Error FenceSync11::set()
+gl::Error FenceSync11::set(GLenum condition, GLbitfield flags)
{
+ ASSERT(condition == GL_SYNC_GPU_COMMANDS_COMPLETE && flags == 0);
return FenceSetHelper(this);
}
@@ -168,7 +168,7 @@ gl::Error FenceSync11::clientWait(GLbitfield flags, GLuint64 timeout, GLenum *ou
return gl::Error(GL_NO_ERROR);
}
- LARGE_INTEGER currentCounter = { 0 };
+ LARGE_INTEGER currentCounter = {};
BOOL success = QueryPerformanceCounter(&currentCounter);
UNUSED_ASSERTION_VARIABLE(success);
ASSERT(success);
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Fence11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Fence11.h
index 2d87f43e76..595978885b 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Fence11.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Fence11.h
@@ -20,11 +20,11 @@ class FenceNV11 : public FenceNVImpl
{
public:
explicit FenceNV11(Renderer11 *renderer);
- virtual ~FenceNV11();
+ ~FenceNV11() override;
- gl::Error set();
- gl::Error test(bool flushCommandBuffer, GLboolean *outFinished);
- gl::Error finishFence(GLboolean *outFinished);
+ gl::Error set(GLenum condition) override;
+ gl::Error test(GLboolean *outFinished) override;
+ gl::Error finish() override;
private:
template<class T> friend gl::Error FenceSetHelper(T *fence);
@@ -38,12 +38,12 @@ class FenceSync11 : public FenceSyncImpl
{
public:
explicit FenceSync11(Renderer11 *renderer);
- virtual ~FenceSync11();
+ ~FenceSync11() override;
- gl::Error set();
- gl::Error clientWait(GLbitfield flags, GLuint64 timeout, GLenum *outResult);
- gl::Error serverWait(GLbitfield flags, GLuint64 timeout);
- gl::Error getStatus(GLint *outResult);
+ gl::Error set(GLenum condition, GLbitfield flags) override;
+ gl::Error clientWait(GLbitfield flags, GLuint64 timeout, GLenum *outResult) override;
+ gl::Error serverWait(GLbitfield flags, GLuint64 timeout) override;
+ gl::Error getStatus(GLint *outResult) override;
private:
template<class T> friend gl::Error FenceSetHelper(T *fence);
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Framebuffer11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Framebuffer11.cpp
index da01f320c0..186a035902 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Framebuffer11.cpp
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Framebuffer11.cpp
@@ -25,8 +25,7 @@ namespace rx
{
Framebuffer11::Framebuffer11(const gl::Framebuffer::Data &data, Renderer11 *renderer)
- : FramebufferD3D(data, renderer),
- mRenderer(renderer)
+ : FramebufferD3D(data, renderer), mRenderer(renderer)
{
ASSERT(mRenderer != nullptr);
}
@@ -43,7 +42,7 @@ static gl::Error InvalidateAttachmentSwizzles(const gl::FramebufferAttachment *a
TextureD3D *textureD3D = GetImplAs<TextureD3D>(texture);
- TextureStorage *texStorage = NULL;
+ TextureStorage *texStorage = nullptr;
gl::Error error = textureD3D->getNativeTexture(&texStorage);
if (error.isError())
{
@@ -52,7 +51,7 @@ static gl::Error InvalidateAttachmentSwizzles(const gl::FramebufferAttachment *a
if (texStorage)
{
- TextureStorage11 *texStorage11 = TextureStorage11::makeTextureStorage11(texStorage);
+ TextureStorage11 *texStorage11 = GetAs<TextureStorage11>(texStorage);
ASSERT(texStorage11);
texStorage11->invalidateSwizzleCacheLevel(attachment->mipLevel());
@@ -64,23 +63,25 @@ static gl::Error InvalidateAttachmentSwizzles(const gl::FramebufferAttachment *a
gl::Error Framebuffer11::invalidateSwizzles() const
{
- for (auto it = mData.mColorAttachments.cbegin(); it != mData.mColorAttachments.cend(); ++it)
+ for (const auto &colorAttachment : mData.getColorAttachments())
{
- gl::FramebufferAttachment *colorAttachment = *it;
- gl::Error error = InvalidateAttachmentSwizzles(colorAttachment);
- if (error.isError())
+ if (colorAttachment.isAttached())
{
- return error;
+ gl::Error error = InvalidateAttachmentSwizzles(&colorAttachment);
+ if (error.isError())
+ {
+ return error;
+ }
}
}
- gl::Error error = InvalidateAttachmentSwizzles(mData.mDepthAttachment);
+ gl::Error error = InvalidateAttachmentSwizzles(mData.getDepthAttachment());
if (error.isError())
{
return error;
}
- error = InvalidateAttachmentSwizzles(mData.mStencilAttachment);
+ error = InvalidateAttachmentSwizzles(mData.getStencilAttachment());
if (error.isError())
{
return error;
@@ -89,10 +90,30 @@ gl::Error Framebuffer11::invalidateSwizzles() const
return gl::Error(GL_NO_ERROR);
}
-gl::Error Framebuffer11::clear(const gl::State &state, const ClearParameters &clearParams)
+gl::Error Framebuffer11::clear(const gl::Data &data, const ClearParameters &clearParams)
{
Clear11 *clearer = mRenderer->getClearer();
- gl::Error error = clearer->clearFramebuffer(clearParams, mData);
+ gl::Error error(GL_NO_ERROR);
+
+ const gl::FramebufferAttachment *colorAttachment = mData.getFirstColorAttachment();
+ if (clearParams.scissorEnabled == true && colorAttachment != nullptr &&
+ UsePresentPathFast(mRenderer, colorAttachment))
+ {
+ // If the current framebuffer is using the default colorbuffer, and present path fast is
+ // active, and the scissor rect is enabled, then we should invert the scissor rect
+ // vertically
+ ClearParameters presentPathFastClearParams = clearParams;
+ gl::Extents framebufferSize = colorAttachment->getSize();
+ presentPathFastClearParams.scissor.y = framebufferSize.height -
+ presentPathFastClearParams.scissor.y -
+ presentPathFastClearParams.scissor.height;
+ error = clearer->clearFramebuffer(presentPathFastClearParams, mData);
+ }
+ else
+ {
+ error = clearer->clearFramebuffer(clearParams, mData);
+ }
+
if (error.isError())
{
return error;
@@ -107,76 +128,193 @@ gl::Error Framebuffer11::clear(const gl::State &state, const ClearParameters &cl
return gl::Error(GL_NO_ERROR);
}
-static gl::Error getRenderTargetResource(const gl::FramebufferAttachment *colorbuffer, unsigned int *subresourceIndexOut,
- ID3D11Texture2D **texture2DOut)
+gl::Error Framebuffer11::invalidate(size_t count, const GLenum *attachments)
{
- ASSERT(colorbuffer);
+ return invalidateBase(count, attachments, false);
+}
- RenderTarget11 *renderTarget = NULL;
- gl::Error error = d3d11::GetAttachmentRenderTarget(colorbuffer, &renderTarget);
- if (error.isError())
+gl::Error Framebuffer11::discard(size_t count, const GLenum *attachments)
+{
+ return invalidateBase(count, attachments, true);
+}
+
+gl::Error Framebuffer11::invalidateBase(size_t count, const GLenum *attachments, bool useEXTBehavior) const
+{
+#if defined(ANGLE_ENABLE_D3D11_1)
+ ID3D11DeviceContext1 *deviceContext1 = mRenderer->getDeviceContext1IfSupported();
+
+ if (!deviceContext1)
{
- return error;
+ // DiscardView() is only supported on ID3D11DeviceContext1
+ return gl::Error(GL_NO_ERROR);
}
- ID3D11Resource *renderTargetResource = renderTarget->getTexture();
- ASSERT(renderTargetResource);
-
- *subresourceIndexOut = renderTarget->getSubresourceIndex();
- *texture2DOut = d3d11::DynamicCastComObject<ID3D11Texture2D>(renderTargetResource);
+ bool foundDepth = false;
+ bool foundStencil = false;
- if (!(*texture2DOut))
+ for (size_t i = 0; i < count; ++i)
{
- return gl::Error(GL_OUT_OF_MEMORY, "Failed to query the ID3D11Texture2D from a RenderTarget");
- }
+ switch (attachments[i])
+ {
+ // Handle depth and stencil attachments. Defer discarding until later.
+ case GL_DEPTH_STENCIL_ATTACHMENT:
+ foundDepth = true;
+ foundStencil = true;
+ break;
+ case GL_DEPTH_EXT:
+ case GL_DEPTH_ATTACHMENT:
+ foundDepth = true;
+ break;
+ case GL_STENCIL_EXT:
+ case GL_STENCIL_ATTACHMENT:
+ foundStencil = true;
+ break;
+ default:
+ {
+ // Handle color attachments
+ ASSERT((attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT15) ||
+ (attachments[i] == GL_COLOR));
- return gl::Error(GL_NO_ERROR);
-}
+ RenderTarget11 *renderTarget = nullptr;
+ ID3D11View *colorView = nullptr;
+ gl::Error error(GL_NO_ERROR);
+ size_t colorAttachmentID = 0;
-gl::Error Framebuffer11::readPixels(const gl::Rectangle &area, GLenum format, GLenum type, size_t outputPitch, const gl::PixelPackState &pack, uint8_t *pixels) const
-{
- ID3D11Texture2D *colorBufferTexture = NULL;
- unsigned int subresourceIndex = 0;
+ if (attachments[i] == GL_COLOR)
+ {
+ colorAttachmentID = 0;
+ }
+ else
+ {
+ colorAttachmentID = attachments[i] - GL_COLOR_ATTACHMENT0;
+ }
- const gl::FramebufferAttachment *colorbuffer = mData.getReadAttachment();
- ASSERT(colorbuffer);
+ if (mData.getColorAttachment(static_cast<unsigned int>(colorAttachmentID)))
+ {
+ error = mData.getColorAttachment(static_cast<unsigned int>(colorAttachmentID))
+ ->getRenderTarget(&renderTarget);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ colorView = renderTarget->getRenderTargetView();
+
+ if (colorView != nullptr)
+ {
+ deviceContext1->DiscardView(colorView);
+ }
+ }
- gl::Error error = getRenderTargetResource(colorbuffer, &subresourceIndex, &colorBufferTexture);
- if (error.isError())
+ break;
+ }
+ }
+ }
+
+ bool discardDepth = false;
+ bool discardStencil = false;
+
+ // The D3D11 renderer uses the same view for depth and stencil buffers, so we must be careful.
+ if (useEXTBehavior)
{
- return error;
+ // In the extension, if the app discards only one of the depth and stencil attachments, but
+ // those are backed by the same packed_depth_stencil buffer, then both images become undefined.
+ discardDepth = foundDepth;
+
+ // Don't bother discarding the stencil buffer if the depth buffer will already do it
+ discardStencil = foundStencil && (!discardDepth || mData.getDepthAttachment() == nullptr);
+ }
+ else
+ {
+ // In ES 3.0.4, if a specified attachment has base internal format DEPTH_STENCIL but the
+ // attachments list does not include DEPTH_STENCIL_ATTACHMENT or both DEPTH_ATTACHMENT and
+ // STENCIL_ATTACHMENT, then only the specified portion of every pixel in the subregion of pixels
+ // of the DEPTH_STENCIL buffer may be invalidated, and the other portion must be preserved.
+ discardDepth = (foundDepth && foundStencil) || (foundDepth && (mData.getStencilAttachment() == nullptr));
+ discardStencil = (foundStencil && (mData.getDepthAttachment() == nullptr));
}
- gl::Buffer *packBuffer = pack.pixelBuffer.get();
- if (packBuffer != NULL)
+ if (discardDepth && mData.getDepthAttachment())
{
- Buffer11 *packBufferStorage = Buffer11::makeBuffer11(packBuffer->getImplementation());
- PackPixelsParams packParams(area, format, type, outputPitch, pack, reinterpret_cast<ptrdiff_t>(pixels));
+ RenderTarget11 *renderTarget = nullptr;
+ ID3D11View *depthView = nullptr;
+ gl::Error error(GL_NO_ERROR);
- error = packBufferStorage->packPixels(colorBufferTexture, subresourceIndex, packParams);
+ error = mData.getDepthAttachment()->getRenderTarget(&renderTarget);
if (error.isError())
{
- SafeRelease(colorBufferTexture);
return error;
}
- packBuffer->getIndexRangeCache()->clear();
+ depthView = renderTarget->getDepthStencilView();
+
+ if (depthView != nullptr)
+ {
+ deviceContext1->DiscardView(depthView);
+ }
}
- else
+
+ if (discardStencil && mData.getStencilAttachment())
{
- error = mRenderer->readTextureData(colorBufferTexture, subresourceIndex, area, format, type, outputPitch, pack, pixels);
+ RenderTarget11 *renderTarget = nullptr;
+ ID3D11View *stencilView = nullptr;
+ gl::Error error(GL_NO_ERROR);
+
+ error = mData.getStencilAttachment()->getRenderTarget(&renderTarget);
if (error.isError())
{
- SafeRelease(colorBufferTexture);
return error;
}
+
+ stencilView = renderTarget->getDepthStencilView();
+
+ if (stencilView != nullptr)
+ {
+ deviceContext1->DiscardView(stencilView);
+ }
}
+#endif // ANGLE_ENABLE_D3D11_1
- SafeRelease(colorBufferTexture);
+ return gl::Error(GL_NO_ERROR);
+}
+gl::Error Framebuffer11::invalidateSub(size_t, const GLenum *, const gl::Rectangle &)
+{
+ // A no-op implementation conforms to the spec, so don't call UNIMPLEMENTED()
return gl::Error(GL_NO_ERROR);
}
+gl::Error Framebuffer11::readPixelsImpl(const gl::Rectangle &area,
+ GLenum format,
+ GLenum type,
+ size_t outputPitch,
+ const gl::PixelPackState &pack,
+ uint8_t *pixels) const
+{
+ const gl::FramebufferAttachment *readAttachment = mData.getReadAttachment();
+ ASSERT(readAttachment);
+
+ gl::Buffer *packBuffer = pack.pixelBuffer.get();
+ if (packBuffer != nullptr)
+ {
+ if (pack.rowLength != 0 || pack.skipRows != 0 || pack.skipPixels != 0)
+ {
+ UNIMPLEMENTED();
+ return gl::Error(GL_INVALID_OPERATION,
+ "Unimplemented pixel store parameters in readPixelsImpl");
+ }
+
+ Buffer11 *packBufferStorage = GetImplAs<Buffer11>(packBuffer);
+ PackPixelsParams packParams(area, format, type, static_cast<GLuint>(outputPitch), pack,
+ reinterpret_cast<ptrdiff_t>(pixels));
+
+ return packBufferStorage->packPixels(*readAttachment, packParams);
+ }
+
+ return mRenderer->readFromAttachment(*readAttachment, area, format, type,
+ static_cast<GLuint>(outputPitch), pack, pixels);
+}
+
gl::Error Framebuffer11::blit(const gl::Rectangle &sourceArea, const gl::Rectangle &destArea, const gl::Rectangle *scissor,
bool blitRenderTarget, bool blitDepth, bool blitStencil, GLenum filter,
const gl::Framebuffer *sourceFramebuffer)
@@ -186,31 +324,53 @@ gl::Error Framebuffer11::blit(const gl::Rectangle &sourceArea, const gl::Rectang
const gl::FramebufferAttachment *readBuffer = sourceFramebuffer->getReadColorbuffer();
ASSERT(readBuffer);
- RenderTargetD3D *readRenderTarget = NULL;
- gl::Error error = GetAttachmentRenderTarget(readBuffer, &readRenderTarget);
+ RenderTargetD3D *readRenderTarget = nullptr;
+ gl::Error error = readBuffer->getRenderTarget(&readRenderTarget);
if (error.isError())
{
return error;
}
ASSERT(readRenderTarget);
- for (size_t colorAttachment = 0; colorAttachment < mData.mColorAttachments.size(); colorAttachment++)
+ const auto &colorAttachments = mData.getColorAttachments();
+ const auto &drawBufferStates = mData.getDrawBufferStates();
+
+ for (size_t colorAttachment = 0; colorAttachment < colorAttachments.size(); colorAttachment++)
{
- if (mData.mColorAttachments[colorAttachment] != nullptr &&
- mData.mDrawBufferStates[colorAttachment] != GL_NONE)
- {
- const gl::FramebufferAttachment *drawBuffer = mData.mColorAttachments[colorAttachment];
+ const gl::FramebufferAttachment &drawBuffer = colorAttachments[colorAttachment];
- RenderTargetD3D *drawRenderTarget = NULL;
- error = GetAttachmentRenderTarget(drawBuffer, &drawRenderTarget);
+ if (drawBuffer.isAttached() &&
+ drawBufferStates[colorAttachment] != GL_NONE)
+ {
+ RenderTargetD3D *drawRenderTarget = nullptr;
+ error = drawBuffer.getRenderTarget(&drawRenderTarget);
if (error.isError())
{
return error;
}
ASSERT(drawRenderTarget);
- error = mRenderer->blitRenderbufferRect(sourceArea, destArea, readRenderTarget, drawRenderTarget,
- filter, scissor, blitRenderTarget, false, false);
+ const bool invertColorSource = UsePresentPathFast(mRenderer, readBuffer);
+ gl::Rectangle actualSourceArea = sourceArea;
+ if (invertColorSource)
+ {
+ RenderTarget11 *readRenderTarget11 = GetAs<RenderTarget11>(readRenderTarget);
+ actualSourceArea.y = readRenderTarget11->getHeight() - sourceArea.y;
+ actualSourceArea.height = -sourceArea.height;
+ }
+
+ const bool invertColorDest = UsePresentPathFast(mRenderer, &drawBuffer);
+ gl::Rectangle actualDestArea = destArea;
+ if (invertColorDest)
+ {
+ RenderTarget11 *drawRenderTarget11 = GetAs<RenderTarget11>(drawRenderTarget);
+ actualDestArea.y = drawRenderTarget11->getHeight() - destArea.y;
+ actualDestArea.height = -destArea.height;
+ }
+
+ error = mRenderer->blitRenderbufferRect(actualSourceArea, actualDestArea,
+ readRenderTarget, drawRenderTarget, filter,
+ scissor, blitRenderTarget, false, false);
if (error.isError())
{
return error;
@@ -221,11 +381,11 @@ gl::Error Framebuffer11::blit(const gl::Rectangle &sourceArea, const gl::Rectang
if (blitDepth || blitStencil)
{
- gl::FramebufferAttachment *readBuffer = sourceFramebuffer->getDepthOrStencilbuffer();
+ const gl::FramebufferAttachment *readBuffer = sourceFramebuffer->getDepthOrStencilbuffer();
ASSERT(readBuffer);
- RenderTargetD3D *readRenderTarget = NULL;
- gl::Error error = GetAttachmentRenderTarget(readBuffer, &readRenderTarget);
+ RenderTargetD3D *readRenderTarget = nullptr;
+ gl::Error error = readBuffer->getRenderTarget(&readRenderTarget);
if (error.isError())
{
return error;
@@ -235,8 +395,8 @@ gl::Error Framebuffer11::blit(const gl::Rectangle &sourceArea, const gl::Rectang
const gl::FramebufferAttachment *drawBuffer = mData.getDepthOrStencilAttachment();
ASSERT(drawBuffer);
- RenderTargetD3D *drawRenderTarget = NULL;
- error = GetAttachmentRenderTarget(drawBuffer, &drawRenderTarget);
+ RenderTargetD3D *drawRenderTarget = nullptr;
+ error = drawBuffer->getRenderTarget(&drawRenderTarget);
if (error.isError())
{
return error;
@@ -262,7 +422,7 @@ gl::Error Framebuffer11::blit(const gl::Rectangle &sourceArea, const gl::Rectang
GLenum Framebuffer11::getRenderTargetImplementationFormat(RenderTargetD3D *renderTarget) const
{
- RenderTarget11 *renderTarget11 = RenderTarget11::makeRenderTarget11(renderTarget);
+ RenderTarget11 *renderTarget11 = GetAs<RenderTarget11>(renderTarget);
const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(renderTarget11->getDXGIFormat());
return dxgiFormatInfo.internalFormat;
}
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Framebuffer11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Framebuffer11.h
index 07fa480fa2..c8a33ec7e5 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Framebuffer11.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Framebuffer11.h
@@ -21,19 +21,28 @@ class Framebuffer11 : public FramebufferD3D
Framebuffer11(const gl::Framebuffer::Data &data, Renderer11 *renderer);
virtual ~Framebuffer11();
+ gl::Error discard(size_t count, const GLenum *attachments) override;
+ gl::Error invalidate(size_t count, const GLenum *attachments) override;
+ gl::Error invalidateSub(size_t count, const GLenum *attachments, const gl::Rectangle &area) override;
+
// Invalidate the cached swizzles of all bound texture attachments.
gl::Error invalidateSwizzles() const;
private:
- gl::Error clear(const gl::State &state, const ClearParameters &clearParams) override;
+ gl::Error clear(const gl::Data &data, const ClearParameters &clearParams) override;
- gl::Error readPixels(const gl::Rectangle &area, GLenum format, GLenum type, size_t outputPitch,
- const gl::PixelPackState &pack, uint8_t *pixels) const override;
+ gl::Error readPixelsImpl(const gl::Rectangle &area,
+ GLenum format,
+ GLenum type,
+ size_t outputPitch,
+ const gl::PixelPackState &pack,
+ uint8_t *pixels) const override;
gl::Error blit(const gl::Rectangle &sourceArea, const gl::Rectangle &destArea, const gl::Rectangle *scissor,
bool blitRenderTarget, bool blitDepth, bool blitStencil, GLenum filter,
const gl::Framebuffer *sourceFramebuffer) override;
+ gl::Error invalidateBase(size_t count, const GLenum *attachments, bool useEXTBehavior) const;
GLenum getRenderTargetImplementationFormat(RenderTargetD3D *renderTarget) const override;
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Image11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Image11.cpp
index 956b78b5a6..c52092d81e 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Image11.cpp
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Image11.cpp
@@ -7,17 +7,18 @@
// Image11.h: Implements the rx::Image11 class, which acts as the interface to
// the actual underlying resources of a Texture
-#include "libANGLE/renderer/d3d/d3d11/Renderer11.h"
#include "libANGLE/renderer/d3d/d3d11/Image11.h"
-#include "libANGLE/renderer/d3d/d3d11/RenderTarget11.h"
-#include "libANGLE/renderer/d3d/d3d11/TextureStorage11.h"
-#include "libANGLE/renderer/d3d/d3d11/formatutils11.h"
-#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h"
-#include "libANGLE/Framebuffer.h"
-#include "libANGLE/FramebufferAttachment.h"
-#include "libANGLE/formatutils.h"
#include "common/utilities.h"
+#include "libANGLE/formatutils.h"
+#include "libANGLE/Framebuffer.h"
+#include "libANGLE/FramebufferAttachment.h"
+#include "libANGLE/renderer/d3d/d3d11/formatutils11.h"
+#include "libANGLE/renderer/d3d/d3d11/Renderer11.h"
+#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h"
+#include "libANGLE/renderer/d3d/d3d11/RenderTarget11.h"
+#include "libANGLE/renderer/d3d/d3d11/texture_format_table.h"
+#include "libANGLE/renderer/d3d/d3d11/TextureStorage11.h"
namespace rx
{
@@ -32,9 +33,6 @@ Image11::Image11(Renderer11 *renderer)
mAssociatedImageIndex(gl::ImageIndex::MakeInvalid()),
mRecoveredFromStorageCount(0)
{
- // mRenderer should remain unchanged during the lifetime of the Image11 object.
- // This lets us safely use mRenderer (and its Feature Level) in Image11's methods.
- mFeatureLevel = renderer->getFeatureLevel();
}
Image11::~Image11()
@@ -43,12 +41,6 @@ Image11::~Image11()
releaseStagingTexture();
}
-Image11 *Image11::makeImage11(ImageD3D *img)
-{
- ASSERT(HAS_DYNAMIC_TYPE(Image11*, img));
- return static_cast<Image11*>(img);
-}
-
gl::Error Image11::generateMipmap(Image11 *dest, Image11 *src)
{
ASSERT(src->getDXGIFormat() == dest->getDXGIFormat());
@@ -94,9 +86,14 @@ bool Image11::isDirty() const
// AND mStagingTexture doesn't exist AND mStagingTexture doesn't need to be recovered from TextureStorage
// AND the texture doesn't require init data (i.e. a blank new texture will suffice)
// then isDirty should still return false.
- if (mDirty && !mStagingTexture && !mRecoverFromStorage && !(d3d11::GetTextureFormatInfo(mInternalFormat, mFeatureLevel).dataInitializerFunction != NULL))
+ if (mDirty && !mStagingTexture && !mRecoverFromStorage)
{
- return false;
+ const Renderer11DeviceCaps &deviceCaps = mRenderer->getRenderer11DeviceCaps();
+ const d3d11::TextureFormat formatInfo = d3d11::GetTextureFormatInfo(mInternalFormat, deviceCaps);
+ if (formatInfo.dataInitializerFunction == nullptr)
+ {
+ return false;
+ }
}
return mDirty;
@@ -104,7 +101,7 @@ bool Image11::isDirty() const
gl::Error Image11::copyToStorage(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box &region)
{
- TextureStorage11 *storage11 = TextureStorage11::makeTextureStorage11(storage);
+ TextureStorage11 *storage11 = GetAs<TextureStorage11>(storage);
// If an app's behavior results in an Image11 copying its data to/from to a TextureStorage multiple times,
// then we should just keep the staging texture around to prevent the copying from impacting perf.
@@ -222,7 +219,7 @@ bool Image11::redefine(GLenum target, GLenum internalformat, const gl::Extents &
mTarget = target;
// compute the d3d format that will be used
- const d3d11::TextureFormat &formatInfo = d3d11::GetTextureFormatInfo(internalformat, mFeatureLevel);
+ const d3d11::TextureFormat &formatInfo = d3d11::GetTextureFormatInfo(internalformat, mRenderer->getRenderer11DeviceCaps());
mDXGIFormat = formatInfo.texFormat;
mRenderable = (formatInfo.rtvFormat != DXGI_FORMAT_UNKNOWN);
@@ -250,13 +247,16 @@ gl::Error Image11::loadData(const gl::Box &area, const gl::PixelUnpackState &unp
{
const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(mInternalFormat);
GLsizei inputRowPitch = formatInfo.computeRowPitch(type, area.width, unpack.alignment, unpack.rowLength);
- GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, area.width, area.height, unpack.alignment, unpack.rowLength);
+ GLsizei inputDepthPitch = formatInfo.computeDepthPitch(
+ type, area.width, area.height, unpack.alignment, unpack.rowLength, unpack.imageHeight);
+ GLsizei inputSkipBytes = formatInfo.computeSkipPixels(
+ inputRowPitch, inputDepthPitch, unpack.skipImages, unpack.skipRows, unpack.skipPixels);
const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(mDXGIFormat);
GLuint outputPixelSize = dxgiFormatInfo.pixelBytes;
- const d3d11::TextureFormat &d3dFormatInfo = d3d11::GetTextureFormatInfo(mInternalFormat, mFeatureLevel);
- LoadImageFunction loadFunction = d3dFormatInfo.loadFunctions.at(type);
+ const d3d11::TextureFormat &d3dFormatInfo = d3d11::GetTextureFormatInfo(mInternalFormat, mRenderer->getRenderer11DeviceCaps());
+ LoadImageFunction loadFunction = d3dFormatInfo.loadFunctions.at(type).loadFunction;
D3D11_MAPPED_SUBRESOURCE mappedImage;
gl::Error error = map(D3D11_MAP_WRITE, &mappedImage);
@@ -267,8 +267,8 @@ gl::Error Image11::loadData(const gl::Box &area, const gl::PixelUnpackState &unp
uint8_t *offsetMappedData = (reinterpret_cast<uint8_t*>(mappedImage.pData) + (area.y * mappedImage.RowPitch + area.x * outputPixelSize + area.z * mappedImage.DepthPitch));
loadFunction(area.width, area.height, area.depth,
- reinterpret_cast<const uint8_t*>(input), inputRowPitch, inputDepthPitch,
- offsetMappedData, mappedImage.RowPitch, mappedImage.DepthPitch);
+ reinterpret_cast<const uint8_t *>(input) + inputSkipBytes, inputRowPitch,
+ inputDepthPitch, offsetMappedData, mappedImage.RowPitch, mappedImage.DepthPitch);
unmap();
@@ -279,7 +279,8 @@ gl::Error Image11::loadCompressedData(const gl::Box &area, const void *input)
{
const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(mInternalFormat);
GLsizei inputRowPitch = formatInfo.computeRowPitch(GL_UNSIGNED_BYTE, area.width, 1, 0);
- GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, area.width, area.height, 1, 0);
+ GLsizei inputDepthPitch =
+ formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, area.width, area.height, 1, 0, 0);
const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(mDXGIFormat);
GLuint outputPixelSize = dxgiFormatInfo.pixelBytes;
@@ -289,8 +290,8 @@ gl::Error Image11::loadCompressedData(const gl::Box &area, const void *input)
ASSERT(area.x % outputBlockWidth == 0);
ASSERT(area.y % outputBlockHeight == 0);
- const d3d11::TextureFormat &d3dFormatInfo = d3d11::GetTextureFormatInfo(mInternalFormat, mFeatureLevel);
- LoadImageFunction loadFunction = d3dFormatInfo.loadFunctions.at(GL_UNSIGNED_BYTE);
+ const d3d11::TextureFormat &d3dFormatInfo = d3d11::GetTextureFormatInfo(mInternalFormat, mRenderer->getRenderer11DeviceCaps());
+ LoadImageFunction loadFunction = d3dFormatInfo.loadFunctions.at(GL_UNSIGNED_BYTE).loadFunction;
D3D11_MAPPED_SUBRESOURCE mappedImage;
gl::Error error = map(D3D11_MAP_WRITE, &mappedImage);
@@ -312,180 +313,159 @@ gl::Error Image11::loadCompressedData(const gl::Box &area, const void *input)
return gl::Error(GL_NO_ERROR);
}
-gl::Error Image11::copy(const gl::Offset &destOffset, const gl::Rectangle &sourceArea, RenderTargetD3D *source)
-{
- RenderTarget11 *sourceRenderTarget = RenderTarget11::makeRenderTarget11(source);
- ASSERT(sourceRenderTarget->getTexture());
-
- ID3D11Resource *resource = sourceRenderTarget->getTexture();
- UINT subresourceIndex = sourceRenderTarget->getSubresourceIndex();
-
- gl::Box sourceBox(sourceArea.x, sourceArea.y, 0, sourceArea.width, sourceArea.height, 1);
- gl::Error error = copy(destOffset, sourceBox, resource, subresourceIndex);
-
- SafeRelease(resource);
-
- return error;
-}
-
-gl::Error Image11::copy(const gl::Offset &destOffset, const gl::Box &sourceArea, const gl::ImageIndex &sourceIndex, TextureStorage *source)
+gl::Error Image11::copyFromTexStorage(const gl::ImageIndex &imageIndex, TextureStorage *source)
{
- TextureStorage11 *sourceStorage11 = TextureStorage11::makeTextureStorage11(source);
+ TextureStorage11 *storage11 = GetAs<TextureStorage11>(source);
- UINT subresourceIndex = sourceStorage11->getSubresourceIndex(sourceIndex);
- ID3D11Resource *resource = NULL;
- gl::Error error = sourceStorage11->getResource(&resource);
+ ID3D11Resource *resource = nullptr;
+ gl::Error error = storage11->getResource(&resource);
if (error.isError())
{
return error;
}
- error = copy(destOffset, sourceArea, resource, subresourceIndex);
-
- SafeRelease(resource);
+ UINT subresourceIndex = storage11->getSubresourceIndex(imageIndex);
+ TextureHelper11 textureHelper = TextureHelper11::MakeAndReference(resource);
- return error;
+ gl::Box sourceBox(0, 0, 0, mWidth, mHeight, mDepth);
+ return copyWithoutConversion(gl::Offset(), sourceBox, textureHelper, subresourceIndex);
}
-gl::Error Image11::copy(const gl::Offset &destOffset, const gl::Box &sourceArea, ID3D11Resource *source, UINT sourceSubResource)
+gl::Error Image11::copyFromFramebuffer(const gl::Offset &destOffset,
+ const gl::Rectangle &sourceArea,
+ const gl::Framebuffer *sourceFBO)
{
- D3D11_RESOURCE_DIMENSION dim;
- source->GetType(&dim);
-
- DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN;
- gl::Extents extents;
- UINT sampleCount = 0;
+ const gl::FramebufferAttachment *srcAttachment = sourceFBO->getReadColorbuffer();
+ ASSERT(srcAttachment);
- ID3D11Texture2D *source2D = NULL;
+ const auto &d3d11Format = d3d11::GetTextureFormatInfo(srcAttachment->getInternalFormat(),
+ mRenderer->getRenderer11DeviceCaps());
- if (dim == D3D11_RESOURCE_DIMENSION_TEXTURE2D)
- {
- D3D11_TEXTURE2D_DESC textureDesc2D;
- source2D = d3d11::DynamicCastComObject<ID3D11Texture2D>(source);
- ASSERT(source2D);
- source2D->GetDesc(&textureDesc2D);
-
- format = textureDesc2D.Format;
- extents = gl::Extents(textureDesc2D.Width, textureDesc2D.Height, 1);
- sampleCount = textureDesc2D.SampleDesc.Count;
- }
- else if (dim == D3D11_RESOURCE_DIMENSION_TEXTURE3D)
+ if (d3d11Format.texFormat == mDXGIFormat)
{
- D3D11_TEXTURE3D_DESC textureDesc3D;
- ID3D11Texture3D *source3D = d3d11::DynamicCastComObject<ID3D11Texture3D>(source);
- ASSERT(source3D);
- source3D->GetDesc(&textureDesc3D);
-
- format = textureDesc3D.Format;
- extents = gl::Extents(textureDesc3D.Width, textureDesc3D.Height, textureDesc3D.Depth);
- sampleCount = 1;
- }
- else
- {
- UNREACHABLE();
- }
-
- if (format == mDXGIFormat)
- {
- // No conversion needed-- use copyback fastpath
- ID3D11Resource *stagingTexture = NULL;
- unsigned int stagingSubresourceIndex = 0;
- gl::Error error = getStagingTexture(&stagingTexture, &stagingSubresourceIndex);
+ RenderTargetD3D *renderTarget = nullptr;
+ gl::Error error = srcAttachment->getRenderTarget(&renderTarget);
if (error.isError())
{
return error;
}
- ID3D11Device *device = mRenderer->getDevice();
- ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
+ RenderTarget11 *rt11 = GetAs<RenderTarget11>(renderTarget);
+ ASSERT(rt11->getTexture());
- UINT subresourceAfterResolve = sourceSubResource;
+ TextureHelper11 textureHelper = TextureHelper11::MakeAndReference(rt11->getTexture());
+ unsigned int sourceSubResource = rt11->getSubresourceIndex();
- ID3D11Resource *srcTex = NULL;
+ gl::Box sourceBox(sourceArea.x, sourceArea.y, 0, sourceArea.width, sourceArea.height, 1);
+ return copyWithoutConversion(destOffset, sourceBox, textureHelper, sourceSubResource);
+ }
- bool needResolve = (dim == D3D11_RESOURCE_DIMENSION_TEXTURE2D && sampleCount > 1);
+ // This format requires conversion, so we must copy the texture to staging and manually convert
+ // via readPixels
+ D3D11_MAPPED_SUBRESOURCE mappedImage;
+ gl::Error error = map(D3D11_MAP_WRITE, &mappedImage);
+ if (error.isError())
+ {
+ return error;
+ }
- if (needResolve)
- {
- D3D11_TEXTURE2D_DESC resolveDesc;
- resolveDesc.Width = extents.width;
- resolveDesc.Height = extents.height;
- resolveDesc.MipLevels = 1;
- resolveDesc.ArraySize = 1;
- resolveDesc.Format = format;
- resolveDesc.SampleDesc.Count = 1;
- resolveDesc.SampleDesc.Quality = 0;
- resolveDesc.Usage = D3D11_USAGE_DEFAULT;
- resolveDesc.BindFlags = 0;
- resolveDesc.CPUAccessFlags = 0;
- resolveDesc.MiscFlags = 0;
-
- ID3D11Texture2D *srcTex2D = NULL;
- HRESULT result = device->CreateTexture2D(&resolveDesc, NULL, &srcTex2D);
- if (FAILED(result))
- {
- return gl::Error(GL_OUT_OF_MEMORY, "Failed to create resolve texture for Image11::copy, HRESULT: 0x%X.", result);
- }
- srcTex = srcTex2D;
+ // determine the offset coordinate into the destination buffer
+ const auto &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(mDXGIFormat);
+ GLsizei rowOffset = dxgiFormatInfo.pixelBytes * destOffset.x;
- deviceContext->ResolveSubresource(srcTex, 0, source, sourceSubResource, format);
- subresourceAfterResolve = 0;
- }
- else
- {
- srcTex = source;
- }
+ uint8_t *dataOffset = static_cast<uint8_t *>(mappedImage.pData) +
+ mappedImage.RowPitch * destOffset.y + rowOffset +
+ destOffset.z * mappedImage.DepthPitch;
- D3D11_BOX srcBox;
- srcBox.left = sourceArea.x;
- srcBox.right = sourceArea.x + sourceArea.width;
- srcBox.top = sourceArea.y;
- srcBox.bottom = sourceArea.y + sourceArea.height;
- srcBox.front = sourceArea.z;
- srcBox.back = sourceArea.z + sourceArea.depth;
+ const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(mInternalFormat);
- deviceContext->CopySubresourceRegion(stagingTexture, stagingSubresourceIndex, destOffset.x, destOffset.y,
- destOffset.z, srcTex, subresourceAfterResolve, &srcBox);
+ error = mRenderer->readFromAttachment(*srcAttachment, sourceArea, formatInfo.format,
+ formatInfo.type, mappedImage.RowPitch,
+ gl::PixelPackState(), dataOffset);
- if (needResolve)
- {
- SafeRelease(srcTex);
- }
- }
- else
+ unmap();
+ mDirty = true;
+
+ return error;
+}
+
+gl::Error Image11::copyWithoutConversion(const gl::Offset &destOffset,
+ const gl::Box &sourceArea,
+ const TextureHelper11 &textureHelper,
+ UINT sourceSubResource)
+{
+ // No conversion needed-- use copyback fastpath
+ ID3D11Resource *stagingTexture = nullptr;
+ unsigned int stagingSubresourceIndex = 0;
+ gl::Error error = getStagingTexture(&stagingTexture, &stagingSubresourceIndex);
+ if (error.isError())
{
- // This format requires conversion, so we must copy the texture to staging and manually convert via readPixels
- D3D11_MAPPED_SUBRESOURCE mappedImage;
- gl::Error error = map(D3D11_MAP_WRITE, &mappedImage);
- if (error.isError())
- {
- return error;
- }
+ return error;
+ }
- // determine the offset coordinate into the destination buffer
- const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(mDXGIFormat);
- GLsizei rowOffset = dxgiFormatInfo.pixelBytes * destOffset.x;
- uint8_t *dataOffset = static_cast<uint8_t*>(mappedImage.pData) + mappedImage.RowPitch * destOffset.y + rowOffset + destOffset.z * mappedImage.DepthPitch;
+ ID3D11Device *device = mRenderer->getDevice();
+ ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
- const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(mInternalFormat);
+ UINT subresourceAfterResolve = sourceSubResource;
- // Currently in ANGLE, the source data may only need to be converted if the source is the current framebuffer
- // and OpenGL ES framebuffers must be 2D textures therefore we should not need to convert 3D textures between different formats.
- ASSERT(dim == D3D11_RESOURCE_DIMENSION_TEXTURE2D);
- ASSERT(sourceArea.z == 0 && sourceArea.depth == 1);
- gl::Rectangle sourceRect(sourceArea.x, sourceArea.y, sourceArea.width, sourceArea.height);
- error = mRenderer->readTextureData(source2D, sourceSubResource, sourceRect, formatInfo.format, formatInfo.type, mappedImage.RowPitch, gl::PixelPackState(), dataOffset);
+ ID3D11Resource *srcTex = nullptr;
+ const gl::Extents &extents = textureHelper.getExtents();
- unmap();
+ bool needResolve =
+ (textureHelper.getTextureType() == GL_TEXTURE_2D && textureHelper.getSampleCount() > 1);
- if (error.isError())
+ if (needResolve)
+ {
+ D3D11_TEXTURE2D_DESC resolveDesc;
+ resolveDesc.Width = extents.width;
+ resolveDesc.Height = extents.height;
+ resolveDesc.MipLevels = 1;
+ resolveDesc.ArraySize = 1;
+ resolveDesc.Format = textureHelper.getFormat();
+ resolveDesc.SampleDesc.Count = 1;
+ resolveDesc.SampleDesc.Quality = 0;
+ resolveDesc.Usage = D3D11_USAGE_DEFAULT;
+ resolveDesc.BindFlags = 0;
+ resolveDesc.CPUAccessFlags = 0;
+ resolveDesc.MiscFlags = 0;
+
+ ID3D11Texture2D *srcTex2D = NULL;
+ HRESULT result = device->CreateTexture2D(&resolveDesc, NULL, &srcTex2D);
+ if (FAILED(result))
{
- return error;
+ return gl::Error(GL_OUT_OF_MEMORY,
+ "Failed to create resolve texture for Image11::copy, HRESULT: 0x%X.",
+ result);
}
+ srcTex = srcTex2D;
+
+ deviceContext->ResolveSubresource(srcTex, 0, textureHelper.getTexture2D(),
+ sourceSubResource, textureHelper.getFormat());
+ subresourceAfterResolve = 0;
+ }
+ else
+ {
+ srcTex = textureHelper.getResource();
}
- mDirty = true;
+ D3D11_BOX srcBox;
+ srcBox.left = sourceArea.x;
+ srcBox.right = sourceArea.x + sourceArea.width;
+ srcBox.top = sourceArea.y;
+ srcBox.bottom = sourceArea.y + sourceArea.height;
+ srcBox.front = sourceArea.z;
+ srcBox.back = sourceArea.z + sourceArea.depth;
+
+ deviceContext->CopySubresourceRegion(stagingTexture, stagingSubresourceIndex, destOffset.x,
+ destOffset.y, destOffset.z, srcTex,
+ subresourceAfterResolve, &srcBox);
+
+ if (needResolve)
+ {
+ SafeRelease(srcTex);
+ }
+ mDirty = true;
return gl::Error(GL_NO_ERROR);
}
@@ -543,11 +523,11 @@ gl::Error Image11::createStagingTexture()
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
desc.MiscFlags = 0;
- if (d3d11::GetTextureFormatInfo(mInternalFormat, mFeatureLevel).dataInitializerFunction != NULL)
+ if (d3d11::GetTextureFormatInfo(mInternalFormat, mRenderer->getRenderer11DeviceCaps()).dataInitializerFunction != NULL)
{
std::vector<D3D11_SUBRESOURCE_DATA> initialData;
- std::vector< std::vector<BYTE> > textureData;
- d3d11::GenerateInitialTextureData(mInternalFormat, mFeatureLevel, width, height, mDepth,
+ std::vector<std::vector<BYTE>> textureData;
+ d3d11::GenerateInitialTextureData(mInternalFormat, mRenderer->getRenderer11DeviceCaps(), width, height, mDepth,
lodOffset + 1, &initialData, &textureData);
result = device->CreateTexture3D(&desc, initialData.data(), &newTexture);
@@ -583,11 +563,11 @@ gl::Error Image11::createStagingTexture()
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
desc.MiscFlags = 0;
- if (d3d11::GetTextureFormatInfo(mInternalFormat, mFeatureLevel).dataInitializerFunction != NULL)
+ if (d3d11::GetTextureFormatInfo(mInternalFormat, mRenderer->getRenderer11DeviceCaps()).dataInitializerFunction != NULL)
{
std::vector<D3D11_SUBRESOURCE_DATA> initialData;
- std::vector< std::vector<BYTE> > textureData;
- d3d11::GenerateInitialTextureData(mInternalFormat, mFeatureLevel, width, height, 1,
+ std::vector<std::vector<BYTE>> textureData;
+ d3d11::GenerateInitialTextureData(mInternalFormat, mRenderer->getRenderer11DeviceCaps(), width, height, 1,
lodOffset + 1, &initialData, &textureData);
result = device->CreateTexture2D(&desc, initialData.data(), &newTexture);
@@ -637,13 +617,13 @@ gl::Error Image11::map(D3D11_MAP mapType, D3D11_MAPPED_SUBRESOURCE *map)
ASSERT(mStagingTexture);
HRESULT result = deviceContext->Map(stagingTexture, subresourceIndex, mapType, 0, map);
- // this can fail if the device is removed (from TDR)
- if (d3d11::isDeviceLostError(result))
- {
- mRenderer->notifyDeviceLost();
- }
- else if (FAILED(result))
+ if (FAILED(result))
{
+ // this can fail if the device is removed (from TDR)
+ if (d3d11::isDeviceLostError(result))
+ {
+ mRenderer->notifyDeviceLost();
+ }
return gl::Error(GL_OUT_OF_MEMORY, "Failed to map staging texture, result: 0x%X.", result);
}
@@ -661,4 +641,4 @@ void Image11::unmap()
}
}
-}
+} // namespace rx
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Image11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Image11.h
index 5734f73b15..a5fcec84f8 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Image11.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Image11.h
@@ -23,6 +23,7 @@ class Framebuffer;
namespace rx
{
class Renderer11;
+class TextureHelper11;
class TextureStorage11;
class Image11 : public ImageD3D
@@ -31,8 +32,6 @@ class Image11 : public ImageD3D
Image11(Renderer11 *renderer);
virtual ~Image11();
- static Image11 *makeImage11(ImageD3D *img);
-
static gl::Error generateMipmap(Image11 *dest, Image11 *src);
virtual bool isDirty() const;
@@ -46,9 +45,10 @@ class Image11 : public ImageD3D
virtual gl::Error loadData(const gl::Box &area, const gl::PixelUnpackState &unpack, GLenum type, const void *input);
virtual gl::Error loadCompressedData(const gl::Box &area, const void *input);
- virtual gl::Error copy(const gl::Offset &destOffset, const gl::Rectangle &sourceArea, RenderTargetD3D *source);
- virtual gl::Error copy(const gl::Offset &destOffset, const gl::Box &sourceArea,
- const gl::ImageIndex &sourceIndex, TextureStorage *source);
+ gl::Error copyFromTexStorage(const gl::ImageIndex &imageIndex, TextureStorage *source) override;
+ gl::Error copyFromFramebuffer(const gl::Offset &destOffset,
+ const gl::Rectangle &sourceArea,
+ const gl::Framebuffer *source) override;
gl::Error recoverFromAssociatedStorage();
bool isAssociatedStorageValid(TextureStorage11* textureStorage) const;
@@ -59,15 +59,16 @@ class Image11 : public ImageD3D
void unmap();
private:
- gl::Error copyToStorageImpl(TextureStorage11 *storage11, const gl::ImageIndex &index, const gl::Box &region);
- gl::Error copy(const gl::Offset &destOffset, const gl::Box &sourceArea, ID3D11Resource *source, UINT sourceSubResource);
+ gl::Error copyWithoutConversion(const gl::Offset &destOffset,
+ const gl::Box &sourceArea,
+ const TextureHelper11 &textureHelper,
+ UINT sourceSubResource);
gl::Error getStagingTexture(ID3D11Resource **outStagingTexture, unsigned int *outSubresourceIndex);
gl::Error createStagingTexture();
void releaseStagingTexture();
Renderer11 *mRenderer;
- D3D_FEATURE_LEVEL mFeatureLevel;
DXGI_FORMAT mDXGIFormat;
ID3D11Resource *mStagingTexture;
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/IndexBuffer11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/IndexBuffer11.cpp
index 99c199f2b9..a5e78a245d 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/IndexBuffer11.cpp
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/IndexBuffer11.cpp
@@ -7,7 +7,9 @@
// IndexBuffer11.cpp: Defines the D3D11 IndexBuffer implementation.
#include "libANGLE/renderer/d3d/d3d11/IndexBuffer11.h"
+
#include "libANGLE/renderer/d3d/d3d11/Renderer11.h"
+#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h"
namespace rx
{
@@ -47,6 +49,15 @@ gl::Error IndexBuffer11::initialize(unsigned int bufferSize, GLenum indexType, b
{
return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal index buffer of size, %lu.", bufferSize);
}
+
+ if (dynamic)
+ {
+ d3d11::SetDebugName(mBuffer, "IndexBuffer11 (dynamic)");
+ }
+ else
+ {
+ d3d11::SetDebugName(mBuffer, "IndexBuffer11 (static)");
+ }
}
mBufferSize = bufferSize;
@@ -56,12 +67,6 @@ gl::Error IndexBuffer11::initialize(unsigned int bufferSize, GLenum indexType, b
return gl::Error(GL_NO_ERROR);
}
-IndexBuffer11 *IndexBuffer11::makeIndexBuffer11(IndexBuffer *indexBuffer)
-{
- ASSERT(HAS_DYNAMIC_TYPE(IndexBuffer11*, indexBuffer));
- return static_cast<IndexBuffer11*>(indexBuffer);
-}
-
gl::Error IndexBuffer11::mapBuffer(unsigned int offset, unsigned int size, void** outMappedMemory)
{
if (!mBuffer)
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/IndexBuffer11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/IndexBuffer11.h
index eadd03eb76..e730377e00 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/IndexBuffer11.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/IndexBuffer11.h
@@ -23,8 +23,6 @@ class IndexBuffer11 : public IndexBuffer
virtual gl::Error initialize(unsigned int bufferSize, GLenum indexType, bool dynamic);
- static IndexBuffer11 *makeIndexBuffer11(IndexBuffer *indexBuffer);
-
virtual gl::Error mapBuffer(unsigned int offset, unsigned int size, void** outMappedMemory);
virtual gl::Error unmapBuffer();
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/InputLayoutCache.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/InputLayoutCache.cpp
index 242c09d6ce..3a6d797ea6 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/InputLayoutCache.cpp
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/InputLayoutCache.cpp
@@ -8,43 +8,141 @@
// D3D11 input layouts.
#include "libANGLE/renderer/d3d/d3d11/InputLayoutCache.h"
-#include "libANGLE/renderer/d3d/d3d11/VertexBuffer11.h"
+
+#include "common/utilities.h"
+#include "libANGLE/Program.h"
+#include "libANGLE/VertexAttribute.h"
+#include "libANGLE/renderer/d3d/IndexDataManager.h"
+#include "libANGLE/renderer/d3d/ProgramD3D.h"
+#include "libANGLE/renderer/d3d/VertexDataManager.h"
#include "libANGLE/renderer/d3d/d3d11/Buffer11.h"
#include "libANGLE/renderer/d3d/d3d11/ShaderExecutable11.h"
+#include "libANGLE/renderer/d3d/d3d11/VertexBuffer11.h"
#include "libANGLE/renderer/d3d/d3d11/formatutils11.h"
-#include "libANGLE/renderer/d3d/ProgramD3D.h"
-#include "libANGLE/renderer/d3d/VertexDataManager.h"
-#include "libANGLE/Program.h"
-#include "libANGLE/VertexAttribute.h"
-
#include "third_party/murmurhash/MurmurHash3.h"
namespace rx
{
-static void GetInputLayout(const TranslatedAttribute translatedAttributes[gl::MAX_VERTEX_ATTRIBS],
- gl::VertexFormat inputLayout[gl::MAX_VERTEX_ATTRIBS])
+namespace
+{
+
+size_t GetReservedBufferCount(bool usesPointSpriteEmulation)
{
- for (unsigned int attributeIndex = 0; attributeIndex < gl::MAX_VERTEX_ATTRIBS; attributeIndex++)
+ return usesPointSpriteEmulation ? 1 : 0;
+}
+
+gl::InputLayout GetInputLayout(const SortedAttribArray &translatedAttributes, size_t attributeCount)
+{
+ gl::InputLayout inputLayout(attributeCount, gl::VERTEX_FORMAT_INVALID);
+
+ for (size_t attributeIndex = 0; attributeIndex < attributeCount; ++attributeIndex)
{
- const TranslatedAttribute &translatedAttribute = translatedAttributes[attributeIndex];
+ const TranslatedAttribute *translatedAttribute = translatedAttributes[attributeIndex];
+
+ if (translatedAttribute->active)
+ {
+ inputLayout[attributeIndex] = gl::GetVertexFormatType(
+ *translatedAttribute->attribute, translatedAttribute->currentValueType);
+ }
+ }
+ return inputLayout;
+}
+
+GLenum GetGLSLAttributeType(const std::vector<sh::Attribute> &shaderAttributes, int index)
+{
+ // Count matrices differently
+ for (const sh::Attribute &attrib : shaderAttributes)
+ {
+ if (attrib.location == -1)
+ {
+ continue;
+ }
+
+ GLenum transposedType = gl::TransposeMatrixType(attrib.type);
+ int rows = gl::VariableRowCount(transposedType);
+
+ if (index >= attrib.location && index < attrib.location + rows)
+ {
+ return transposedType;
+ }
+ }
+
+ UNREACHABLE();
+ return GL_NONE;
+}
+
+const unsigned int kDefaultCacheSize = 1024;
+
+struct PackedAttribute
+{
+ uint8_t attribType;
+ uint8_t semanticIndex;
+ uint8_t vertexFormatType;
+ uint8_t divisor;
+};
- if (translatedAttributes[attributeIndex].active)
+Optional<size_t> FindFirstNonInstanced(const SortedAttribArray &sortedAttributes, size_t maxIndex)
+{
+ for (size_t index = 0; index < maxIndex; ++index)
+ {
+ if (sortedAttributes[index]->divisor == 0)
{
- inputLayout[attributeIndex] = gl::VertexFormat(*translatedAttribute.attribute,
- translatedAttribute.currentValueType);
+ return Optional<size_t>(index);
}
}
+
+ return Optional<size_t>::Invalid();
}
-const unsigned int InputLayoutCache::kMaxInputLayouts = 1024;
+} // anonymous namespace
+
+void InputLayoutCache::PackedAttributeLayout::addAttributeData(
+ GLenum glType,
+ UINT semanticIndex,
+ gl::VertexFormatType vertexFormatType,
+ unsigned int divisor)
+{
+ gl::AttributeType attribType = gl::GetAttributeType(glType);
+
+ PackedAttribute packedAttrib;
+ packedAttrib.attribType = static_cast<uint8_t>(attribType);
+ packedAttrib.semanticIndex = static_cast<uint8_t>(semanticIndex);
+ packedAttrib.vertexFormatType = static_cast<uint8_t>(vertexFormatType);
+ packedAttrib.divisor = static_cast<uint8_t>(divisor);
+
+ ASSERT(static_cast<gl::AttributeType>(packedAttrib.attribType) == attribType);
+ ASSERT(static_cast<UINT>(packedAttrib.semanticIndex) == semanticIndex);
+ ASSERT(static_cast<gl::VertexFormatType>(packedAttrib.vertexFormatType) == vertexFormatType);
+ ASSERT(static_cast<unsigned int>(packedAttrib.divisor) == divisor);
+
+ static_assert(sizeof(uint32_t) == sizeof(PackedAttribute), "PackedAttributes must be 32-bits exactly.");
+
+ attributeData[numAttributes++] = gl::bitCast<uint32_t>(packedAttrib);
+}
+
+bool InputLayoutCache::PackedAttributeLayout::operator<(const PackedAttributeLayout &other) const
+{
+ if (numAttributes != other.numAttributes)
+ {
+ return numAttributes < other.numAttributes;
+ }
+
+ if (flags != other.flags)
+ {
+ return flags < other.flags;
+ }
+
+ return memcmp(attributeData, other.attributeData, sizeof(uint32_t) * numAttributes) < 0;
+}
-InputLayoutCache::InputLayoutCache() : mInputLayoutMap(kMaxInputLayouts, hashInputLayout, compareInputLayouts)
+InputLayoutCache::InputLayoutCache() : mUnsortedAttributesCount(0), mCacheSize(kDefaultCacheSize)
{
mCounter = 0;
mDevice = NULL;
mDeviceContext = NULL;
mCurrentIL = NULL;
+
for (unsigned int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
{
mCurrentBuffers[i] = NULL;
@@ -70,11 +168,11 @@ void InputLayoutCache::initialize(ID3D11Device *device, ID3D11DeviceContext *con
void InputLayoutCache::clear()
{
- for (InputLayoutMap::iterator i = mInputLayoutMap.begin(); i != mInputLayoutMap.end(); i++)
+ for (auto &layout : mLayoutMap)
{
- SafeRelease(i->second.inputLayout);
+ SafeRelease(layout.second);
}
- mInputLayoutMap.clear();
+ mLayoutMap.clear();
SafeRelease(mPointSpriteVertexBuffer);
SafeRelease(mPointSpriteIndexBuffer);
markDirty();
@@ -89,236 +187,135 @@ void InputLayoutCache::markDirty()
mCurrentVertexStrides[i] = static_cast<UINT>(-1);
mCurrentVertexOffsets[i] = static_cast<UINT>(-1);
}
+ mUnsortedAttributesCount = 0;
}
-gl::Error InputLayoutCache::applyVertexBuffers(TranslatedAttribute attributes[gl::MAX_VERTEX_ATTRIBS],
- GLenum mode, gl::Program *program)
+gl::Error InputLayoutCache::applyVertexBuffers(
+ const std::vector<TranslatedAttribute> &unsortedAttributes,
+ GLenum mode,
+ gl::Program *program,
+ TranslatedIndexData *indexInfo,
+ GLsizei numIndicesPerInstance)
{
+ ASSERT(mDevice && mDeviceContext);
+
ProgramD3D *programD3D = GetImplAs<ProgramD3D>(program);
- int sortedSemanticIndices[gl::MAX_VERTEX_ATTRIBS];
- programD3D->sortAttributesByLayout(attributes, sortedSemanticIndices);
bool programUsesInstancedPointSprites = programD3D->usesPointSize() && programD3D->usesInstancedPointSpriteEmulation();
bool instancedPointSpritesActive = programUsesInstancedPointSprites && (mode == GL_POINTS);
- if (!mDevice || !mDeviceContext)
- {
- return gl::Error(GL_OUT_OF_MEMORY, "Internal input layout cache is not initialized.");
- }
-
- InputLayoutKey ilKey = { 0 };
-
- static const char* semanticName = "TEXCOORD";
+ SortedIndexArray sortedSemanticIndices;
+ mSortedAttributes.fill(nullptr);
+ mUnsortedAttributesCount = unsortedAttributes.size();
- unsigned int firstIndexedElement = gl::MAX_VERTEX_ATTRIBS;
- unsigned int firstInstancedElement = gl::MAX_VERTEX_ATTRIBS;
- unsigned int nextAvailableInputSlot = 0;
+ programD3D->sortAttributesByLayout(unsortedAttributes, sortedSemanticIndices.data(),
+ mSortedAttributes.data());
- for (unsigned int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
+ // If we are using FL 9_3, make sure the first attribute is not instanced
+ if (mFeatureLevel <= D3D_FEATURE_LEVEL_9_3 && !unsortedAttributes.empty())
{
- if (attributes[i].active)
+ if (mSortedAttributes[0]->divisor > 0)
{
- D3D11_INPUT_CLASSIFICATION inputClass = attributes[i].divisor > 0 ? D3D11_INPUT_PER_INSTANCE_DATA : D3D11_INPUT_PER_VERTEX_DATA;
- // If rendering points and instanced pointsprite emulation is being used, the inputClass is required to be configured as per instance data
- inputClass = instancedPointSpritesActive ? D3D11_INPUT_PER_INSTANCE_DATA : inputClass;
-
- gl::VertexFormat vertexFormat(*attributes[i].attribute, attributes[i].currentValueType);
- const d3d11::VertexFormat &vertexFormatInfo = d3d11::GetVertexFormatInfo(vertexFormat, mFeatureLevel);
-
- // Record the type of the associated vertex shader vector in our key
- // This will prevent mismatched vertex shaders from using the same input layout
- GLint attributeSize;
- program->getActiveAttribute(ilKey.elementCount, 0, NULL, &attributeSize, &ilKey.elements[ilKey.elementCount].glslElementType, NULL);
-
- ilKey.elements[ilKey.elementCount].desc.SemanticName = semanticName;
- ilKey.elements[ilKey.elementCount].desc.SemanticIndex = sortedSemanticIndices[i];
- ilKey.elements[ilKey.elementCount].desc.Format = vertexFormatInfo.nativeFormat;
- ilKey.elements[ilKey.elementCount].desc.InputSlot = i;
- ilKey.elements[ilKey.elementCount].desc.AlignedByteOffset = 0;
- ilKey.elements[ilKey.elementCount].desc.InputSlotClass = inputClass;
- ilKey.elements[ilKey.elementCount].desc.InstanceDataStepRate = instancedPointSpritesActive ? 1 : attributes[i].divisor;
-
- if (inputClass == D3D11_INPUT_PER_VERTEX_DATA && firstIndexedElement == gl::MAX_VERTEX_ATTRIBS)
+ Optional<size_t> firstNonInstancedIndex =
+ FindFirstNonInstanced(mSortedAttributes, unsortedAttributes.size());
+ if (firstNonInstancedIndex.valid())
{
- firstIndexedElement = ilKey.elementCount;
+ size_t index = firstNonInstancedIndex.value();
+ std::swap(mSortedAttributes[0], mSortedAttributes[index]);
+ std::swap(sortedSemanticIndices[0], sortedSemanticIndices[index]);
}
- else if (inputClass == D3D11_INPUT_PER_INSTANCE_DATA && firstInstancedElement == gl::MAX_VERTEX_ATTRIBS)
- {
- firstInstancedElement = ilKey.elementCount;
- }
-
- ilKey.elementCount++;
- nextAvailableInputSlot = i + 1;
}
}
- // Instanced PointSprite emulation requires additional entries in the
- // inputlayout to support the vertices that make up the pointsprite quad.
- // We do this even if mode != GL_POINTS, since the shader signature has these inputs, and the input layout must match the shader
- if (programUsesInstancedPointSprites)
+ gl::Error error = updateInputLayout(program, mode, mSortedAttributes, sortedSemanticIndices,
+ unsortedAttributes.size(), numIndicesPerInstance);
+ if (error.isError())
{
- ilKey.elements[ilKey.elementCount].desc.SemanticName = "SPRITEPOSITION";
- ilKey.elements[ilKey.elementCount].desc.SemanticIndex = 0;
- ilKey.elements[ilKey.elementCount].desc.Format = DXGI_FORMAT_R32G32B32_FLOAT;
- ilKey.elements[ilKey.elementCount].desc.InputSlot = nextAvailableInputSlot;
- ilKey.elements[ilKey.elementCount].desc.AlignedByteOffset = 0;
- ilKey.elements[ilKey.elementCount].desc.InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
- ilKey.elements[ilKey.elementCount].desc.InstanceDataStepRate = 0;
-
- // The new elements are D3D11_INPUT_PER_VERTEX_DATA data so the indexed element
- // tracking must be applied. This ensures that the instancing specific
- // buffer swapping logic continues to work.
- if (firstIndexedElement == gl::MAX_VERTEX_ATTRIBS)
- {
- firstIndexedElement = ilKey.elementCount;
- }
-
- ilKey.elementCount++;
-
- ilKey.elements[ilKey.elementCount].desc.SemanticName = "SPRITETEXCOORD";
- ilKey.elements[ilKey.elementCount].desc.SemanticIndex = 0;
- ilKey.elements[ilKey.elementCount].desc.Format = DXGI_FORMAT_R32G32_FLOAT;
- ilKey.elements[ilKey.elementCount].desc.InputSlot = nextAvailableInputSlot;
- ilKey.elements[ilKey.elementCount].desc.AlignedByteOffset = sizeof(float) * 3;
- ilKey.elements[ilKey.elementCount].desc.InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
- ilKey.elements[ilKey.elementCount].desc.InstanceDataStepRate = 0;
-
- ilKey.elementCount++;
+ return error;
}
- // On 9_3, we must ensure that slot 0 contains non-instanced data.
- // If slot 0 currently contains instanced data then we swap it with a non-instanced element.
- // Note that instancing is only available on 9_3 via ANGLE_instanced_arrays, since 9_3 doesn't support OpenGL ES 3.0.
- // As per the spec for ANGLE_instanced_arrays, not all attributes can be instanced simultaneously, so a non-instanced element must exist.
- ASSERT(!(mFeatureLevel <= D3D_FEATURE_LEVEL_9_3 && firstIndexedElement == gl::MAX_VERTEX_ATTRIBS));
- bool moveFirstIndexedIntoSlotZero = mFeatureLevel <= D3D_FEATURE_LEVEL_9_3 && firstInstancedElement == 0 && firstIndexedElement != gl::MAX_VERTEX_ATTRIBS;
-
- if (moveFirstIndexedIntoSlotZero)
- {
- ilKey.elements[firstInstancedElement].desc.InputSlot = ilKey.elements[firstIndexedElement].desc.InputSlot;
- ilKey.elements[firstIndexedElement].desc.InputSlot = 0;
-
- // Instanced PointSprite emulation uses multiple layout entries across a single vertex buffer.
- // If an index swap is performed, we need to ensure that all elements get the proper InputSlot.
- if (programUsesInstancedPointSprites)
- {
- ilKey.elements[firstIndexedElement + 1].desc.InputSlot = 0;
- }
- }
+ bool dirtyBuffers = false;
+ size_t minDiff = gl::MAX_VERTEX_ATTRIBS;
+ size_t maxDiff = 0;
- ID3D11InputLayout *inputLayout = NULL;
+ // Note that if we use instance emulation, we reserve the first buffer slot.
+ size_t reservedBuffers = GetReservedBufferCount(programUsesInstancedPointSprites);
- InputLayoutMap::iterator keyIter = mInputLayoutMap.find(ilKey);
- if (keyIter != mInputLayoutMap.end())
- {
- inputLayout = keyIter->second.inputLayout;
- keyIter->second.lastUsedTime = mCounter++;
- }
- else
+ for (size_t attribIndex = 0; attribIndex < (gl::MAX_VERTEX_ATTRIBS - reservedBuffers);
+ ++attribIndex)
{
- gl::VertexFormat shaderInputLayout[gl::MAX_VERTEX_ATTRIBS];
- GetInputLayout(attributes, shaderInputLayout);
-
- ShaderExecutableD3D *shader = NULL;
- gl::Error error = programD3D->getVertexExecutableForInputLayout(shaderInputLayout, &shader, nullptr);
- if (error.isError())
- {
- return error;
- }
-
- ShaderExecutableD3D *shader11 = ShaderExecutable11::makeShaderExecutable11(shader);
+ ID3D11Buffer *buffer = NULL;
+ UINT vertexStride = 0;
+ UINT vertexOffset = 0;
- D3D11_INPUT_ELEMENT_DESC descs[gl::MAX_VERTEX_ATTRIBS];
- for (unsigned int j = 0; j < ilKey.elementCount; ++j)
- {
- descs[j] = ilKey.elements[j].desc;
- }
+ const auto &attrib = *mSortedAttributes[attribIndex];
- HRESULT result = mDevice->CreateInputLayout(descs, ilKey.elementCount, shader11->getFunction(), shader11->getLength(), &inputLayout);
- if (FAILED(result))
+ if (attribIndex < unsortedAttributes.size() && attrib.active)
{
- return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal input layout, HRESULT: 0x%08x", result);
- }
-
- if (mInputLayoutMap.size() >= kMaxInputLayouts)
- {
- TRACE("Overflowed the limit of %u input layouts, removing the least recently used "
- "to make room.", kMaxInputLayouts);
-
- InputLayoutMap::iterator leastRecentlyUsed = mInputLayoutMap.begin();
- for (InputLayoutMap::iterator i = mInputLayoutMap.begin(); i != mInputLayoutMap.end(); i++)
+ VertexBuffer11 *vertexBuffer = GetAs<VertexBuffer11>(attrib.vertexBuffer);
+ Buffer11 *bufferStorage = attrib.storage ? GetAs<Buffer11>(attrib.storage) : nullptr;
+
+ // If indexed pointsprite emulation is active, then we need to take a less efficent code path.
+ // Emulated indexed pointsprite rendering requires that the vertex buffers match exactly to
+ // the indices passed by the caller. This could expand or shrink the vertex buffer depending
+ // on the number of points indicated by the index list or how many duplicates are found on the index list.
+ if (bufferStorage == nullptr)
{
- if (i->second.lastUsedTime < leastRecentlyUsed->second.lastUsedTime)
+ buffer = vertexBuffer->getBuffer();
+ }
+ else if (instancedPointSpritesActive && (indexInfo != nullptr))
+ {
+ if (indexInfo->srcIndexData.srcBuffer != nullptr)
{
- leastRecentlyUsed = i;
+ const uint8_t *bufferData = nullptr;
+ error = indexInfo->srcIndexData.srcBuffer->getData(&bufferData);
+ if (error.isError())
+ {
+ return error;
+ }
+ ASSERT(bufferData != nullptr);
+
+ ptrdiff_t offset =
+ reinterpret_cast<ptrdiff_t>(indexInfo->srcIndexData.srcIndices);
+ indexInfo->srcIndexData.srcBuffer = nullptr;
+ indexInfo->srcIndexData.srcIndices = bufferData + offset;
}
- }
- SafeRelease(leastRecentlyUsed->second.inputLayout);
- mInputLayoutMap.erase(leastRecentlyUsed);
- }
-
- InputLayoutCounterPair inputCounterPair;
- inputCounterPair.inputLayout = inputLayout;
- inputCounterPair.lastUsedTime = mCounter++;
-
- mInputLayoutMap.insert(std::make_pair(ilKey, inputCounterPair));
- }
-
- if (inputLayout != mCurrentIL)
- {
- mDeviceContext->IASetInputLayout(inputLayout);
- mCurrentIL = inputLayout;
- }
- bool dirtyBuffers = false;
- size_t minDiff = gl::MAX_VERTEX_ATTRIBS;
- size_t maxDiff = 0;
- unsigned int nextAvailableIndex = 0;
-
- for (unsigned int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
- {
- ID3D11Buffer *buffer = NULL;
-
- if (attributes[i].active)
- {
- VertexBuffer11 *vertexBuffer = VertexBuffer11::makeVertexBuffer11(attributes[i].vertexBuffer);
- Buffer11 *bufferStorage = attributes[i].storage ? Buffer11::makeBuffer11(attributes[i].storage) : NULL;
+ buffer = bufferStorage->getEmulatedIndexedBuffer(&indexInfo->srcIndexData, &attrib);
+ }
+ else
+ {
+ buffer = bufferStorage->getBuffer(BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK);
+ }
- buffer = bufferStorage ? bufferStorage->getBuffer(BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK)
- : vertexBuffer->getBuffer();
+ vertexStride = attrib.stride;
+ vertexOffset = attrib.offset;
}
- UINT vertexStride = attributes[i].stride;
- UINT vertexOffset = attributes[i].offset;
+ size_t bufferIndex = reservedBuffers + attribIndex;
- if (buffer != mCurrentBuffers[i] || vertexStride != mCurrentVertexStrides[i] ||
- vertexOffset != mCurrentVertexOffsets[i])
+ if (buffer != mCurrentBuffers[bufferIndex] ||
+ vertexStride != mCurrentVertexStrides[bufferIndex] ||
+ vertexOffset != mCurrentVertexOffsets[bufferIndex])
{
dirtyBuffers = true;
- minDiff = std::min(minDiff, static_cast<size_t>(i));
- maxDiff = std::max(maxDiff, static_cast<size_t>(i));
-
- mCurrentBuffers[i] = buffer;
- mCurrentVertexStrides[i] = vertexStride;
- mCurrentVertexOffsets[i] = vertexOffset;
+ minDiff = std::min(minDiff, bufferIndex);
+ maxDiff = std::max(maxDiff, bufferIndex);
- // If a non null ID3D11Buffer is being assigned to mCurrentBuffers,
- // then the next available index needs to be tracked to ensure
- // that any instanced pointsprite emulation buffers will be properly packed.
- if (buffer)
- {
- nextAvailableIndex = i + 1;
- }
+ mCurrentBuffers[bufferIndex] = buffer;
+ mCurrentVertexStrides[bufferIndex] = vertexStride;
+ mCurrentVertexOffsets[bufferIndex] = vertexOffset;
}
}
- // Instanced PointSprite emulation requires two additional ID3D11Buffers.
- // A vertex buffer needs to be created and added to the list of current buffers,
- // strides and offsets collections. This buffer contains the vertices for a single
- // PointSprite quad.
- // An index buffer also needs to be created and applied because rendering instanced
- // data on D3D11 FL9_3 requires DrawIndexedInstanced() to be used.
- if (instancedPointSpritesActive)
+ // Instanced PointSprite emulation requires two additional ID3D11Buffers. A vertex buffer needs
+ // to be created and added to the list of current buffers, strides and offsets collections.
+ // This buffer contains the vertices for a single PointSprite quad.
+ // An index buffer also needs to be created and applied because rendering instanced data on
+ // D3D11 FL9_3 requires DrawIndexedInstanced() to be used. Shaders that contain gl_PointSize and
+ // used without the GL_POINTS rendering mode require a vertex buffer because some drivers cannot
+ // handle missing vertex data and will TDR the system.
+ if (programUsesInstancedPointSprites)
{
HRESULT result = S_OK;
const UINT pointSpriteVertexStride = sizeof(float) * 5;
@@ -352,9 +349,16 @@ gl::Error InputLayoutCache::applyVertexBuffers(TranslatedAttribute attributes[gl
}
}
- mCurrentBuffers[nextAvailableIndex] = mPointSpriteVertexBuffer;
- mCurrentVertexStrides[nextAvailableIndex] = pointSpriteVertexStride;
- mCurrentVertexOffsets[nextAvailableIndex] = 0;
+ mCurrentBuffers[0] = mPointSpriteVertexBuffer;
+ // Set the stride to 0 if GL_POINTS mode is not being used to instruct the driver to avoid
+ // indexing into the vertex buffer.
+ mCurrentVertexStrides[0] = instancedPointSpritesActive ? pointSpriteVertexStride : 0;
+ mCurrentVertexOffsets[0] = 0;
+
+ // Update maxDiff to include the additional point sprite vertex buffer
+ // to ensure that IASetVertexBuffers uses the correct buffer count.
+ minDiff = 0;
+ maxDiff = std::max(maxDiff, static_cast<size_t>(0));
if (!mPointSpriteIndexBuffer)
{
@@ -381,50 +385,265 @@ gl::Error InputLayoutCache::applyVertexBuffers(TranslatedAttribute attributes[gl
}
}
- // The index buffer is applied here because Instanced PointSprite emulation uses
- // the a non-indexed rendering path in ANGLE (DrawArrays). This means that applyIndexBuffer()
- // on the renderer will not be called and setting this buffer here ensures that the rendering
- // path will contain the correct index buffers.
- mDeviceContext->IASetIndexBuffer(mPointSpriteIndexBuffer, DXGI_FORMAT_R16_UINT, 0);
- }
-
- if (moveFirstIndexedIntoSlotZero)
- {
- // In this case, we swapped the slots of the first instanced element and the first indexed element, to ensure
- // that the first slot contains non-instanced data (required by Feature Level 9_3).
- // We must also swap the corresponding buffers sent to IASetVertexBuffers so that the correct data is sent to each slot.
- std::swap(mCurrentBuffers[firstIndexedElement], mCurrentBuffers[firstInstancedElement]);
- std::swap(mCurrentVertexStrides[firstIndexedElement], mCurrentVertexStrides[firstInstancedElement]);
- std::swap(mCurrentVertexOffsets[firstIndexedElement], mCurrentVertexOffsets[firstInstancedElement]);
+ if (instancedPointSpritesActive)
+ {
+ // The index buffer is applied here because Instanced PointSprite emulation uses the a
+ // non-indexed rendering path in ANGLE (DrawArrays). This means that applyIndexBuffer()
+ // on the renderer will not be called and setting this buffer here ensures that the
+ // rendering path will contain the correct index buffers.
+ mDeviceContext->IASetIndexBuffer(mPointSpriteIndexBuffer, DXGI_FORMAT_R16_UINT, 0);
+ }
}
if (dirtyBuffers)
{
ASSERT(minDiff <= maxDiff && maxDiff < gl::MAX_VERTEX_ATTRIBS);
- mDeviceContext->IASetVertexBuffers(minDiff, maxDiff - minDiff + 1, mCurrentBuffers + minDiff,
- mCurrentVertexStrides + minDiff, mCurrentVertexOffsets + minDiff);
+ mDeviceContext->IASetVertexBuffers(
+ static_cast<UINT>(minDiff), static_cast<UINT>(maxDiff - minDiff + 1),
+ mCurrentBuffers + minDiff, mCurrentVertexStrides + minDiff,
+ mCurrentVertexOffsets + minDiff);
}
return gl::Error(GL_NO_ERROR);
}
-std::size_t InputLayoutCache::hashInputLayout(const InputLayoutKey &inputLayout)
+gl::Error InputLayoutCache::updateVertexOffsetsForPointSpritesEmulation(GLsizei emulatedInstanceId)
{
- static const unsigned int seed = 0xDEADBEEF;
+ size_t reservedBuffers = GetReservedBufferCount(true);
+ for (size_t attribIndex = 0; attribIndex < mUnsortedAttributesCount; ++attribIndex)
+ {
+ const auto &attrib = *mSortedAttributes[attribIndex];
+ size_t bufferIndex = reservedBuffers + attribIndex;
+
+ if (attrib.active && attrib.divisor > 0)
+ {
+ mCurrentVertexOffsets[bufferIndex] =
+ attrib.offset + (attrib.stride * (emulatedInstanceId / attrib.divisor));
+ }
+ }
+
+ mDeviceContext->IASetVertexBuffers(0, gl::MAX_VERTEX_ATTRIBS, mCurrentBuffers,
+ mCurrentVertexStrides, mCurrentVertexOffsets);
- std::size_t hash = 0;
- MurmurHash3_x86_32(inputLayout.begin(), inputLayout.end() - inputLayout.begin(), seed, &hash);
- return hash;
+ return gl::Error(GL_NO_ERROR);
}
-bool InputLayoutCache::compareInputLayouts(const InputLayoutKey &a, const InputLayoutKey &b)
+gl::Error InputLayoutCache::updateInputLayout(gl::Program *program,
+ GLenum mode,
+ const SortedAttribArray &sortedAttributes,
+ const SortedIndexArray &sortedSemanticIndices,
+ size_t attribCount,
+ GLsizei numIndicesPerInstance)
{
- if (a.elementCount != b.elementCount)
+ const std::vector<sh::Attribute> &shaderAttributes = program->getAttributes();
+ PackedAttributeLayout layout;
+
+ ProgramD3D *programD3D = GetImplAs<ProgramD3D>(program);
+ bool programUsesInstancedPointSprites =
+ programD3D->usesPointSize() && programD3D->usesInstancedPointSpriteEmulation();
+ bool instancedPointSpritesActive = programUsesInstancedPointSprites && (mode == GL_POINTS);
+
+ if (programUsesInstancedPointSprites)
+ {
+ layout.flags |= PackedAttributeLayout::FLAG_USES_INSTANCED_SPRITES;
+ }
+
+ if (instancedPointSpritesActive)
{
- return false;
+ layout.flags |= PackedAttributeLayout::FLAG_INSTANCED_SPRITES_ACTIVE;
}
- return std::equal(a.begin(), a.end(), b.begin());
+ if (numIndicesPerInstance > 0)
+ {
+ layout.flags |= PackedAttributeLayout::FLAG_INSTANCED_RENDERING_ACTIVE;
+ }
+
+ const auto &semanticToLocation = programD3D->getAttributesByLayout();
+
+ for (size_t attribIndex = 0; attribIndex < attribCount; ++attribIndex)
+ {
+ const auto &attrib = *sortedAttributes[attribIndex];
+ int sortedIndex = sortedSemanticIndices[attribIndex];
+
+ if (!attrib.active)
+ continue;
+
+ gl::VertexFormatType vertexFormatType =
+ gl::GetVertexFormatType(*attrib.attribute, attrib.currentValueType);
+
+ // Record the type of the associated vertex shader vector in our key
+ // This will prevent mismatched vertex shaders from using the same input layout
+ GLenum glslElementType =
+ GetGLSLAttributeType(shaderAttributes, semanticToLocation[sortedIndex]);
+
+ layout.addAttributeData(glslElementType, sortedIndex, vertexFormatType, attrib.divisor);
+ }
+
+ ID3D11InputLayout *inputLayout = nullptr;
+ if (layout.numAttributes > 0 || layout.flags != 0)
+ {
+ auto layoutMapIt = mLayoutMap.find(layout);
+ if (layoutMapIt != mLayoutMap.end())
+ {
+ inputLayout = layoutMapIt->second;
+ }
+ else
+ {
+ gl::Error error =
+ createInputLayout(sortedAttributes, sortedSemanticIndices, attribCount, mode,
+ program, numIndicesPerInstance, &inputLayout);
+ if (error.isError())
+ {
+ return error;
+ }
+ if (mLayoutMap.size() >= mCacheSize)
+ {
+ TRACE("Overflowed the limit of %u input layouts, purging half the cache.",
+ mCacheSize);
+
+ // Randomly release every second element
+ auto it = mLayoutMap.begin();
+ while (it != mLayoutMap.end())
+ {
+ it++;
+ if (it != mLayoutMap.end())
+ {
+ // c++11 erase allows us to easily delete the current iterator.
+ SafeRelease(it->second);
+ it = mLayoutMap.erase(it);
+ }
+ }
+ }
+
+ mLayoutMap[layout] = inputLayout;
+ }
+ }
+
+ if (inputLayout != mCurrentIL)
+ {
+ mDeviceContext->IASetInputLayout(inputLayout);
+ mCurrentIL = inputLayout;
+ }
+
+ return gl::Error(GL_NO_ERROR);
}
+gl::Error InputLayoutCache::createInputLayout(const SortedAttribArray &sortedAttributes,
+ const SortedIndexArray &sortedSemanticIndices,
+ size_t attribCount,
+ GLenum mode,
+ gl::Program *program,
+ GLsizei numIndicesPerInstance,
+ ID3D11InputLayout **inputLayoutOut)
+{
+ ProgramD3D *programD3D = GetImplAs<ProgramD3D>(program);
+
+ bool programUsesInstancedPointSprites =
+ programD3D->usesPointSize() && programD3D->usesInstancedPointSpriteEmulation();
+
+ unsigned int inputElementCount = 0;
+ std::array<D3D11_INPUT_ELEMENT_DESC, gl::MAX_VERTEX_ATTRIBS> inputElements;
+
+ for (size_t attribIndex = 0; attribIndex < attribCount; ++attribIndex)
+ {
+ const auto &attrib = *sortedAttributes[attribIndex];
+ const int sortedIndex = sortedSemanticIndices[attribIndex];
+
+ if (!attrib.active)
+ continue;
+
+ D3D11_INPUT_CLASSIFICATION inputClass =
+ attrib.divisor > 0 ? D3D11_INPUT_PER_INSTANCE_DATA : D3D11_INPUT_PER_VERTEX_DATA;
+
+ const auto &vertexFormatType =
+ gl::GetVertexFormatType(*attrib.attribute, attrib.currentValueType);
+ const auto &vertexFormatInfo = d3d11::GetVertexFormatInfo(vertexFormatType, mFeatureLevel);
+
+ auto *inputElement = &inputElements[inputElementCount];
+
+ inputElement->SemanticName = "TEXCOORD";
+ inputElement->SemanticIndex = sortedIndex;
+ inputElement->Format = vertexFormatInfo.nativeFormat;
+ inputElement->InputSlot = static_cast<UINT>(attribIndex);
+ inputElement->AlignedByteOffset = 0;
+ inputElement->InputSlotClass = inputClass;
+ inputElement->InstanceDataStepRate = attrib.divisor;
+
+ inputElementCount++;
+ }
+
+ // Instanced PointSprite emulation requires additional entries in the
+ // inputlayout to support the vertices that make up the pointsprite quad.
+ // We do this even if mode != GL_POINTS, since the shader signature has these inputs, and the
+ // input layout must match the shader
+ if (programUsesInstancedPointSprites)
+ {
+ // On 9_3, we must ensure that slot 0 contains non-instanced data.
+ // If slot 0 currently contains instanced data then we swap it with a non-instanced element.
+ // Note that instancing is only available on 9_3 via ANGLE_instanced_arrays, since 9_3
+ // doesn't support OpenGL ES 3.0.
+ // As per the spec for ANGLE_instanced_arrays, not all attributes can be instanced
+ // simultaneously, so a non-instanced element must exist.
+ for (size_t elementIndex = 0; elementIndex < inputElementCount; ++elementIndex)
+ {
+ if (sortedAttributes[elementIndex]->active)
+ {
+ // If rendering points and instanced pointsprite emulation is being used, the
+ // inputClass is required to be configured as per instance data
+ if (mode == GL_POINTS)
+ {
+ inputElements[elementIndex].InputSlotClass = D3D11_INPUT_PER_INSTANCE_DATA;
+ inputElements[elementIndex].InstanceDataStepRate = 1;
+ if (numIndicesPerInstance > 0 && sortedAttributes[elementIndex]->divisor > 0)
+ {
+ inputElements[elementIndex].InstanceDataStepRate = numIndicesPerInstance;
+ }
+ }
+ inputElements[elementIndex].InputSlot++;
+ }
+ }
+
+ inputElements[inputElementCount].SemanticName = "SPRITEPOSITION";
+ inputElements[inputElementCount].SemanticIndex = 0;
+ inputElements[inputElementCount].Format = DXGI_FORMAT_R32G32B32_FLOAT;
+ inputElements[inputElementCount].InputSlot = 0;
+ inputElements[inputElementCount].AlignedByteOffset = 0;
+ inputElements[inputElementCount].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
+ inputElements[inputElementCount].InstanceDataStepRate = 0;
+ inputElementCount++;
+
+ inputElements[inputElementCount].SemanticName = "SPRITETEXCOORD";
+ inputElements[inputElementCount].SemanticIndex = 0;
+ inputElements[inputElementCount].Format = DXGI_FORMAT_R32G32_FLOAT;
+ inputElements[inputElementCount].InputSlot = 0;
+ inputElements[inputElementCount].AlignedByteOffset = sizeof(float) * 3;
+ inputElements[inputElementCount].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
+ inputElements[inputElementCount].InstanceDataStepRate = 0;
+ inputElementCount++;
+ }
+
+ const gl::InputLayout &shaderInputLayout = GetInputLayout(sortedAttributes, attribCount);
+
+ ShaderExecutableD3D *shader = nullptr;
+ gl::Error error =
+ programD3D->getVertexExecutableForInputLayout(shaderInputLayout, &shader, nullptr);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ ShaderExecutableD3D *shader11 = GetAs<ShaderExecutable11>(shader);
+
+ HRESULT result =
+ mDevice->CreateInputLayout(inputElements.data(), inputElementCount, shader11->getFunction(),
+ shader11->getLength(), inputLayoutOut);
+ if (FAILED(result))
+ {
+ return gl::Error(GL_OUT_OF_MEMORY,
+ "Failed to create internal input layout, HRESULT: 0x%08x", result);
+ }
+
+ return gl::Error(GL_NO_ERROR);
}
+
+} // namespace rx
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/InputLayoutCache.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/InputLayoutCache.h
index 2c94c57595..e208ae3c64 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/InputLayoutCache.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/InputLayoutCache.h
@@ -10,14 +10,17 @@
#ifndef LIBANGLE_RENDERER_D3D_D3D11_INPUTLAYOUTCACHE_H_
#define LIBANGLE_RENDERER_D3D_D3D11_INPUTLAYOUTCACHE_H_
-#include "libANGLE/Constants.h"
-#include "libANGLE/Error.h"
-#include "common/angleutils.h"
-
#include <GLES2/gl2.h>
#include <cstddef>
-#include <unordered_map>
+
+#include <array>
+#include <map>
+
+#include "common/angleutils.h"
+#include "libANGLE/Constants.h"
+#include "libANGLE/Error.h"
+#include "libANGLE/formatutils.h"
namespace gl
{
@@ -27,6 +30,12 @@ class Program;
namespace rx
{
struct TranslatedAttribute;
+struct TranslatedIndexData;
+struct SourceIndexData;
+class ProgramD3D;
+
+using SortedAttribArray = std::array<const TranslatedAttribute *, gl::MAX_VERTEX_ATTRIBS>;
+using SortedIndexArray = std::array<int, gl::MAX_VERTEX_ATTRIBS>;
class InputLayoutCache : angle::NonCopyable
{
@@ -38,59 +47,72 @@ class InputLayoutCache : angle::NonCopyable
void clear();
void markDirty();
- gl::Error applyVertexBuffers(TranslatedAttribute attributes[gl::MAX_VERTEX_ATTRIBS],
- GLenum mode, gl::Program *program);
+ gl::Error applyVertexBuffers(const std::vector<TranslatedAttribute> &attributes,
+ GLenum mode,
+ gl::Program *program,
+ TranslatedIndexData *indexInfo,
+ GLsizei numIndicesPerInstance);
- private:
- struct InputLayoutElement
- {
- D3D11_INPUT_ELEMENT_DESC desc;
- GLenum glslElementType;
- };
+ gl::Error updateVertexOffsetsForPointSpritesEmulation(GLsizei emulatedInstanceId);
- struct InputLayoutKey
- {
- unsigned int elementCount;
- InputLayoutElement elements[gl::MAX_VERTEX_ATTRIBS];
+ // Useful for testing
+ void setCacheSize(unsigned int cacheSize) { mCacheSize = cacheSize; }
- const char *begin() const
+ private:
+ struct PackedAttributeLayout
+ {
+ PackedAttributeLayout()
+ : numAttributes(0),
+ flags(0)
{
- return reinterpret_cast<const char*>(&elementCount);
}
- const char *end() const
+ void addAttributeData(GLenum glType,
+ UINT semanticIndex,
+ gl::VertexFormatType vertexFormatType,
+ unsigned int divisor);
+
+ bool operator<(const PackedAttributeLayout &other) const;
+
+ enum Flags
{
- return reinterpret_cast<const char*>(&elements[elementCount]);
- }
+ FLAG_USES_INSTANCED_SPRITES = 0x1,
+ FLAG_INSTANCED_SPRITES_ACTIVE = 0x2,
+ FLAG_INSTANCED_RENDERING_ACTIVE = 0x4,
+ };
+
+ size_t numAttributes;
+ unsigned int flags;
+ uint32_t attributeData[gl::MAX_VERTEX_ATTRIBS];
};
- struct InputLayoutCounterPair
- {
- ID3D11InputLayout *inputLayout;
- unsigned long long lastUsedTime;
- };
+ gl::Error updateInputLayout(gl::Program *program,
+ GLenum mode,
+ const SortedAttribArray &sortedAttributes,
+ const SortedIndexArray &sortedSemanticIndices,
+ size_t attribCount,
+ GLsizei numIndicesPerInstance);
+ gl::Error createInputLayout(const SortedAttribArray &sortedAttributes,
+ const SortedIndexArray &sortedSemanticIndices,
+ size_t attribCount,
+ GLenum mode,
+ gl::Program *program,
+ GLsizei numIndicesPerInstance,
+ ID3D11InputLayout **inputLayoutOut);
+
+ std::map<PackedAttributeLayout, ID3D11InputLayout *> mLayoutMap;
ID3D11InputLayout *mCurrentIL;
ID3D11Buffer *mCurrentBuffers[gl::MAX_VERTEX_ATTRIBS];
UINT mCurrentVertexStrides[gl::MAX_VERTEX_ATTRIBS];
UINT mCurrentVertexOffsets[gl::MAX_VERTEX_ATTRIBS];
+ SortedAttribArray mSortedAttributes;
+ size_t mUnsortedAttributesCount;
ID3D11Buffer *mPointSpriteVertexBuffer;
ID3D11Buffer *mPointSpriteIndexBuffer;
- static std::size_t hashInputLayout(const InputLayoutKey &inputLayout);
- static bool compareInputLayouts(const InputLayoutKey &a, const InputLayoutKey &b);
-
- typedef std::size_t (*InputLayoutHashFunction)(const InputLayoutKey &);
- typedef bool (*InputLayoutEqualityFunction)(const InputLayoutKey &, const InputLayoutKey &);
- typedef std::unordered_map<InputLayoutKey,
- InputLayoutCounterPair,
- InputLayoutHashFunction,
- InputLayoutEqualityFunction> InputLayoutMap;
- InputLayoutMap mInputLayoutMap;
-
- static const unsigned int kMaxInputLayouts;
-
+ unsigned int mCacheSize;
unsigned long long mCounter;
ID3D11Device *mDevice;
@@ -98,6 +120,6 @@ class InputLayoutCache : angle::NonCopyable
D3D_FEATURE_LEVEL mFeatureLevel;
};
-}
+} // namespace rx
#endif // LIBANGLE_RENDERER_D3D_D3D11_INPUTLAYOUTCACHE_H_
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/NativeWindow.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/NativeWindow.h
index 0f70fe4615..612b06bb10 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/NativeWindow.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/NativeWindow.h
@@ -16,6 +16,7 @@
#include "common/platform.h"
#include <EGL/eglplatform.h>
+#include "libANGLE/Config.h"
// DXGISwapChain and DXGIFactory are typedef'd to specific required
// types. The HWND NativeWindow implementation requires IDXGISwapChain
@@ -43,6 +44,10 @@ typedef IDXGISwapChain DXGISwapChain;
typedef IDXGIFactory DXGIFactory;
#endif
+typedef interface IDCompositionDevice IDCompositionDevice;
+typedef interface IDCompositionTarget IDCompositionTarget;
+typedef interface IDCompositionVisual IDCompositionVisual;
+
namespace rx
{
@@ -50,8 +55,11 @@ class NativeWindow
{
public:
enum RotationFlags { RotateNone = 0, RotateLeft = 1, RotateRight = 2 };
- explicit NativeWindow(EGLNativeWindowType window);
+ explicit NativeWindow(EGLNativeWindowType window,
+ const egl::Config *config,
+ bool directComposition);
+ ~NativeWindow();
bool initialize();
bool getClientRect(LPRECT rect);
bool isIconic();
@@ -68,9 +76,16 @@ class NativeWindow
inline EGLNativeWindowType getNativeWindow() const { return mWindow; }
+ void commitChange();
+
private:
EGLNativeWindowType mWindow;
+ bool mDirectComposition;
+ IDCompositionDevice *mDevice;
+ IDCompositionTarget *mCompositionTarget;
+ IDCompositionVisual *mVisual;
+ const egl::Config *mConfig;
#if defined(ANGLE_ENABLE_WINDOWS_STORE)
std::shared_ptr<InspectableNativeWindow> mImpl;
#endif
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/PixelTransfer11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/PixelTransfer11.cpp
index 5fd5237d90..dfc521f14f 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/PixelTransfer11.cpp
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/PixelTransfer11.cpp
@@ -10,23 +10,25 @@
//
#include "libANGLE/renderer/d3d/d3d11/PixelTransfer11.h"
+
+#include "libANGLE/Buffer.h"
+#include "libANGLE/Context.h"
+#include "libANGLE/formatutils.h"
+#include "libANGLE/renderer/d3d/d3d11/Buffer11.h"
+#include "libANGLE/renderer/d3d/d3d11/formatutils11.h"
#include "libANGLE/renderer/d3d/d3d11/Renderer11.h"
#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h"
-#include "libANGLE/renderer/d3d/d3d11/formatutils11.h"
-#include "libANGLE/renderer/d3d/d3d11/Buffer11.h"
-#include "libANGLE/renderer/d3d/d3d11/TextureStorage11.h"
#include "libANGLE/renderer/d3d/d3d11/RenderTarget11.h"
-#include "libANGLE/formatutils.h"
+#include "libANGLE/renderer/d3d/d3d11/texture_format_table.h"
+#include "libANGLE/renderer/d3d/d3d11/TextureStorage11.h"
#include "libANGLE/Texture.h"
-#include "libANGLE/Buffer.h"
-#include "libANGLE/Context.h"
// Precompiled shaders
-#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/buffertotexture11_vs.h"
#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/buffertotexture11_gs.h"
#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/buffertotexture11_ps_4f.h"
#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/buffertotexture11_ps_4i.h"
#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/buffertotexture11_ps_4ui.h"
+#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/buffertotexture11_vs.h"
namespace rx
{
@@ -202,14 +204,14 @@ gl::Error PixelTransfer11::copyBufferToTexture(const gl::PixelUnpackState &unpac
GLenum unsizedFormat = gl::GetInternalFormatInfo(destinationFormat).format;
GLenum sourceFormat = gl::GetSizedInternalFormat(unsizedFormat, sourcePixelsType);
- const d3d11::TextureFormat &sourceFormatInfo = d3d11::GetTextureFormatInfo(sourceFormat, mRenderer->getFeatureLevel());
+ const d3d11::TextureFormat &sourceFormatInfo = d3d11::GetTextureFormatInfo(sourceFormat, mRenderer->getRenderer11DeviceCaps());
DXGI_FORMAT srvFormat = sourceFormatInfo.srvFormat;
ASSERT(srvFormat != DXGI_FORMAT_UNKNOWN);
- Buffer11 *bufferStorage11 = Buffer11::makeBuffer11(sourceBuffer.getImplementation());
+ Buffer11 *bufferStorage11 = GetAs<Buffer11>(sourceBuffer.getImplementation());
ID3D11ShaderResourceView *bufferSRV = bufferStorage11->getSRV(srvFormat);
ASSERT(bufferSRV != NULL);
- ID3D11RenderTargetView *textureRTV = RenderTarget11::makeRenderTarget11(destRenderTarget)->getRenderTargetView();
+ ID3D11RenderTargetView *textureRTV = GetAs<RenderTarget11>(destRenderTarget)->getRenderTargetView();
ASSERT(textureRTV != NULL);
CopyShaderParams shaderParams;
@@ -222,11 +224,12 @@ gl::Error PixelTransfer11::copyBufferToTexture(const gl::PixelUnpackState &unpac
// Are we doing a 2D or 3D copy?
ID3D11GeometryShader *geometryShader = ((destSize.depth > 1) ? mBufferToTextureGS : NULL);
+ auto stateManager = mRenderer->getStateManager();
deviceContext->VSSetShader(mBufferToTextureVS, NULL, 0);
deviceContext->GSSetShader(geometryShader, NULL, 0);
deviceContext->PSSetShader(pixelShader, NULL, 0);
- mRenderer->setShaderResource(gl::SAMPLER_PIXEL, 0, bufferSRV);
+ stateManager->setShaderResource(gl::SAMPLER_PIXEL, 0, bufferSRV);
deviceContext->IASetInputLayout(NULL);
deviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_POINTLIST);
@@ -249,8 +252,8 @@ gl::Error PixelTransfer11::copyBufferToTexture(const gl::PixelUnpackState &unpac
D3D11_VIEWPORT viewport;
viewport.TopLeftX = 0;
viewport.TopLeftY = 0;
- viewport.Width = destSize.width;
- viewport.Height = destSize.height;
+ viewport.Width = static_cast<FLOAT>(destSize.width);
+ viewport.Height = static_cast<FLOAT>(destSize.height);
viewport.MinDepth = 0.0f;
viewport.MaxDepth = 1.0f;
deviceContext->RSSetViewports(1, &viewport);
@@ -259,7 +262,7 @@ gl::Error PixelTransfer11::copyBufferToTexture(const gl::PixelUnpackState &unpac
deviceContext->Draw(numPixels, 0);
// Unbind textures and render targets and vertex buffer
- mRenderer->setShaderResource(gl::SAMPLER_PIXEL, 0, NULL);
+ stateManager->setShaderResource(gl::SAMPLER_PIXEL, 0, NULL);
deviceContext->VSSetConstantBuffers(0, 1, &nullBuffer);
mRenderer->markAllStateDirty();
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Query11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Query11.cpp
index 4979ff51a9..972c289412 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Query11.cpp
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Query11.cpp
@@ -18,7 +18,14 @@ typedef struct D3D11_QUERY_DATA_SO_STATISTICS {
UINT64 NumPrimitivesWritten;
UINT64 PrimitivesStorageNeeded;
} D3D11_QUERY_DATA_SO_STATISTICS;
-#endif
+#endif // ANGLE_MINGW32_COMPAT
+
+#ifdef __MINGW32__
+typedef struct D3D11_QUERY_DATA_TIMESTAMP_DISJOINT {
+ UINT64 Frequency;
+ BOOL Disjoint;
+} D3D11_QUERY_DATA_TIMESTAMP_DISJOINT;
+#endif // MINGW32
namespace rx
{
@@ -28,38 +35,81 @@ Query11::Query11(Renderer11 *renderer, GLenum type)
mResult(0),
mQueryFinished(false),
mRenderer(renderer),
- mQuery(NULL)
+ mQuery(nullptr),
+ mTimestampBeginQuery(nullptr),
+ mTimestampEndQuery(nullptr)
{
}
Query11::~Query11()
{
SafeRelease(mQuery);
+ SafeRelease(mTimestampBeginQuery);
+ SafeRelease(mTimestampEndQuery);
}
gl::Error Query11::begin()
{
- if (mQuery == NULL)
+ if (mQuery == nullptr)
{
D3D11_QUERY_DESC queryDesc;
queryDesc.Query = gl_d3d11::ConvertQueryType(getType());
queryDesc.MiscFlags = 0;
- HRESULT result = mRenderer->getDevice()->CreateQuery(&queryDesc, &mQuery);
+ ID3D11Device *device = mRenderer->getDevice();
+
+ HRESULT result = device->CreateQuery(&queryDesc, &mQuery);
if (FAILED(result))
{
return gl::Error(GL_OUT_OF_MEMORY, "Internal query creation failed, result: 0x%X.", result);
}
+
+ // If we are doing time elapsed we also need a query to actually query the timestamp
+ if (getType() == GL_TIME_ELAPSED_EXT)
+ {
+ D3D11_QUERY_DESC desc;
+ desc.Query = D3D11_QUERY_TIMESTAMP;
+ desc.MiscFlags = 0;
+ result = device->CreateQuery(&desc, &mTimestampBeginQuery);
+ if (FAILED(result))
+ {
+ return gl::Error(GL_OUT_OF_MEMORY, "Internal query creation failed, result: 0x%X.",
+ result);
+ }
+ result = device->CreateQuery(&desc, &mTimestampEndQuery);
+ if (FAILED(result))
+ {
+ return gl::Error(GL_OUT_OF_MEMORY, "Internal query creation failed, result: 0x%X.",
+ result);
+ }
+ }
}
- mRenderer->getDeviceContext()->Begin(mQuery);
+ ID3D11DeviceContext *context = mRenderer->getDeviceContext();
+
+ context->Begin(mQuery);
+
+ // If we are doing time elapsed query the begin timestamp
+ if (getType() == GL_TIME_ELAPSED_EXT)
+ {
+ context->End(mTimestampBeginQuery);
+ }
return gl::Error(GL_NO_ERROR);
}
gl::Error Query11::end()
{
ASSERT(mQuery);
- mRenderer->getDeviceContext()->End(mQuery);
+
+ ID3D11DeviceContext *context = mRenderer->getDeviceContext();
+
+ // If we are doing time elapsed query the end timestamp
+ if (getType() == GL_TIME_ELAPSED_EXT)
+ {
+ context->End(mTimestampEndQuery);
+ }
+
+ context->End(mQuery);
mQueryFinished = false;
mResult = GL_FALSE;
@@ -67,7 +117,17 @@ gl::Error Query11::end()
return gl::Error(GL_NO_ERROR);
}
-gl::Error Query11::getResult(GLuint *params)
+gl::Error Query11::queryCounter()
+{
+ // This doesn't do anything for D3D11 as we don't support timestamps
+ ASSERT(getType() == GL_TIMESTAMP_EXT);
+ mQueryFinished = true;
+ mResult = 0;
+ return gl::Error(GL_NO_ERROR);
+}
+
+template <typename T>
+gl::Error Query11::getResultBase(T *params)
{
while (!mQueryFinished)
{
@@ -84,12 +144,32 @@ gl::Error Query11::getResult(GLuint *params)
}
ASSERT(mQueryFinished);
- *params = mResult;
+ *params = static_cast<T>(mResult);
return gl::Error(GL_NO_ERROR);
}
-gl::Error Query11::isResultAvailable(GLuint *available)
+gl::Error Query11::getResult(GLint *params)
+{
+ return getResultBase(params);
+}
+
+gl::Error Query11::getResult(GLuint *params)
+{
+ return getResultBase(params);
+}
+
+gl::Error Query11::getResult(GLint64 *params)
+{
+ return getResultBase(params);
+}
+
+gl::Error Query11::getResult(GLuint64 *params)
+{
+ return getResultBase(params);
+}
+
+gl::Error Query11::isResultAvailable(bool *available)
{
gl::Error error = testQuery();
if (error.isError())
@@ -97,7 +177,7 @@ gl::Error Query11::isResultAvailable(GLuint *available)
return error;
}
- *available = (mQueryFinished ? GL_TRUE : GL_FALSE);
+ *available = mQueryFinished;
return gl::Error(GL_NO_ERROR);
}
@@ -141,8 +221,74 @@ gl::Error Query11::testQuery()
if (result == S_OK)
{
mQueryFinished = true;
- mResult = static_cast<GLuint>(soStats.NumPrimitivesWritten);
+ mResult = static_cast<GLuint64>(soStats.NumPrimitivesWritten);
+ }
+ }
+ break;
+
+ case GL_TIME_ELAPSED_EXT:
+ {
+ D3D11_QUERY_DATA_TIMESTAMP_DISJOINT timeStats = {0};
+ HRESULT result = context->GetData(mQuery, &timeStats, sizeof(timeStats), 0);
+ if (FAILED(result))
+ {
+ return gl::Error(GL_OUT_OF_MEMORY,
+ "Failed to get the data of an internal query, result: 0x%X.",
+ result);
}
+
+ if (result == S_OK)
+ {
+ UINT64 beginTime = 0;
+ HRESULT beginRes =
+ context->GetData(mTimestampBeginQuery, &beginTime, sizeof(UINT64), 0);
+ if (FAILED(beginRes))
+ {
+ return gl::Error(
+ GL_OUT_OF_MEMORY,
+ "Failed to get the data of an internal query, result: 0x%X.", beginRes);
+ }
+ UINT64 endTime = 0;
+ HRESULT endRes =
+ context->GetData(mTimestampEndQuery, &endTime, sizeof(UINT64), 0);
+ if (FAILED(endRes))
+ {
+ return gl::Error(
+ GL_OUT_OF_MEMORY,
+ "Failed to get the data of an internal query, result: 0x%X.", endRes);
+ }
+
+ if (beginRes == S_OK && endRes == S_OK)
+ {
+ mQueryFinished = true;
+ if (timeStats.Disjoint)
+ {
+ mRenderer->setGPUDisjoint();
+ }
+ static_assert(sizeof(UINT64) == sizeof(unsigned long long),
+ "D3D UINT64 isn't 64 bits");
+ if (rx::IsUnsignedMultiplicationSafe(endTime - beginTime, 1000000000ull))
+ {
+ mResult = ((endTime - beginTime) * 1000000000ull) / timeStats.Frequency;
+ }
+ else
+ {
+ mResult = std::numeric_limits<GLuint64>::max() / timeStats.Frequency;
+ // If an overflow does somehow occur, there is no way the elapsed time
+ // is accurate, so we generate a disjoint event
+ mRenderer->setGPUDisjoint();
+ }
+ }
+ }
+ }
+ break;
+
+ case GL_TIMESTAMP_EXT:
+ {
+ // D3D11 doesn't support GL timestamp queries as D3D timestamps are not guaranteed
+ // to have any sort of continuity outside of a disjoint timestamp query block, which
+ // GL depends on
+ mResult = 0;
}
break;
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Query11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Query11.h
index bd53fed250..29a6e6f85d 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Query11.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Query11.h
@@ -23,18 +23,27 @@ class Query11 : public QueryImpl
virtual gl::Error begin();
virtual gl::Error end();
+ virtual gl::Error queryCounter();
+ virtual gl::Error getResult(GLint *params);
virtual gl::Error getResult(GLuint *params);
- virtual gl::Error isResultAvailable(GLuint *available);
+ virtual gl::Error getResult(GLint64 *params);
+ virtual gl::Error getResult(GLuint64 *params);
+ virtual gl::Error isResultAvailable(bool *available);
private:
gl::Error testQuery();
- GLuint mResult;
+ template <typename T>
+ gl::Error getResultBase(T *params);
+
+ GLuint64 mResult;
bool mQueryFinished;
Renderer11 *mRenderer;
ID3D11Query *mQuery;
+ ID3D11Query *mTimestampBeginQuery;
+ ID3D11Query *mTimestampEndQuery;
};
}
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/RenderStateCache.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/RenderStateCache.cpp
index 4990e6bc6e..2ee25cfb6c 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/RenderStateCache.cpp
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/RenderStateCache.cpp
@@ -21,6 +21,7 @@
namespace rx
{
+using namespace gl_d3d11;
template <typename mapType>
static void ClearStateMap(mapType &map)
@@ -42,12 +43,12 @@ const unsigned int RenderStateCache::kMaxSamplerStates = 4096;
RenderStateCache::RenderStateCache(Renderer11 *renderer)
: mRenderer(renderer),
- mDevice(NULL),
mCounter(0),
mBlendStateCache(kMaxBlendStates, hashBlendState, compareBlendStates),
mRasterizerStateCache(kMaxRasterizerStates, hashRasterizerState, compareRasterizerStates),
mDepthStencilStateCache(kMaxDepthStencilStates, hashDepthStencilState, compareDepthStencilStates),
- mSamplerStateCache(kMaxSamplerStates, hashSamplerState, compareSamplerStates)
+ mSamplerStateCache(kMaxSamplerStates, hashSamplerState, compareSamplerStates),
+ mDevice(NULL)
{
}
@@ -95,9 +96,9 @@ gl::Error RenderStateCache::getBlendState(const gl::Framebuffer *framebuffer, co
bool mrt = false;
const FramebufferD3D *framebufferD3D = GetImplAs<FramebufferD3D>(framebuffer);
- const gl::AttachmentList &colorbuffers = framebufferD3D->getColorAttachmentsForRender(mRenderer->getWorkarounds());
+ const gl::AttachmentList &colorbuffers = framebufferD3D->getColorAttachmentsForRender();
- BlendStateKey key = { 0 };
+ BlendStateKey key = {};
key.blendState = blendState;
for (size_t colorAttachment = 0; colorAttachment < colorbuffers.size(); ++colorAttachment)
{
@@ -209,7 +210,7 @@ gl::Error RenderStateCache::getRasterizerState(const gl::RasterizerState &raster
return gl::Error(GL_OUT_OF_MEMORY, "Internal error, RenderStateCache is not initialized.");
}
- RasterizerStateKey key = { 0 };
+ RasterizerStateKey key = {};
key.rasterizerState = rasterState;
key.scissorEnabled = scissorEnabled;
@@ -297,14 +298,31 @@ bool RenderStateCache::compareDepthStencilStates(const gl::DepthStencilState &a,
return memcmp(&a, &b, sizeof(gl::DepthStencilState)) == 0;
}
-gl::Error RenderStateCache::getDepthStencilState(const gl::DepthStencilState &dsState, ID3D11DepthStencilState **outDSState)
+gl::Error RenderStateCache::getDepthStencilState(const gl::DepthStencilState &originalState,
+ bool disableDepth,
+ bool disableStencil,
+ ID3D11DepthStencilState **outDSState)
{
if (!mDevice)
{
return gl::Error(GL_OUT_OF_MEMORY, "Internal error, RenderStateCache is not initialized.");
}
- DepthStencilStateMap::iterator keyIter = mDepthStencilStateCache.find(dsState);
+ gl::DepthStencilState glState = originalState;
+ if (disableDepth)
+ {
+ glState.depthTest = false;
+ glState.depthMask = false;
+ }
+
+ if (disableStencil)
+ {
+ glState.stencilWritemask = 0;
+ glState.stencilBackWritemask = 0;
+ glState.stencilTest = false;
+ }
+
+ auto keyIter = mDepthStencilStateCache.find(glState);
if (keyIter != mDepthStencilStateCache.end())
{
DepthStencilStateCounterPair &state = keyIter->second;
@@ -312,53 +330,55 @@ gl::Error RenderStateCache::getDepthStencilState(const gl::DepthStencilState &ds
*outDSState = state.first;
return gl::Error(GL_NO_ERROR);
}
- else
+
+ if (mDepthStencilStateCache.size() >= kMaxDepthStencilStates)
{
- if (mDepthStencilStateCache.size() >= kMaxDepthStencilStates)
- {
- TRACE("Overflowed the limit of %u depth stencil states, removing the least recently used "
- "to make room.", kMaxDepthStencilStates);
+ TRACE(
+ "Overflowed the limit of %u depth stencil states, removing the least recently used "
+ "to make room.",
+ kMaxDepthStencilStates);
- DepthStencilStateMap::iterator leastRecentlyUsed = mDepthStencilStateCache.begin();
- for (DepthStencilStateMap::iterator i = mDepthStencilStateCache.begin(); i != mDepthStencilStateCache.end(); i++)
+ auto leastRecentlyUsed = mDepthStencilStateCache.begin();
+ for (auto i = mDepthStencilStateCache.begin(); i != mDepthStencilStateCache.end(); i++)
+ {
+ if (i->second.second < leastRecentlyUsed->second.second)
{
- if (i->second.second < leastRecentlyUsed->second.second)
- {
- leastRecentlyUsed = i;
- }
+ leastRecentlyUsed = i;
}
- SafeRelease(leastRecentlyUsed->second.first);
- mDepthStencilStateCache.erase(leastRecentlyUsed);
}
+ SafeRelease(leastRecentlyUsed->second.first);
+ mDepthStencilStateCache.erase(leastRecentlyUsed);
+ }
- D3D11_DEPTH_STENCIL_DESC dsDesc = { 0 };
- dsDesc.DepthEnable = dsState.depthTest ? TRUE : FALSE;
- dsDesc.DepthWriteMask = gl_d3d11::ConvertDepthMask(dsState.depthMask);
- dsDesc.DepthFunc = gl_d3d11::ConvertComparison(dsState.depthFunc);
- dsDesc.StencilEnable = dsState.stencilTest ? TRUE : FALSE;
- dsDesc.StencilReadMask = gl_d3d11::ConvertStencilMask(dsState.stencilMask);
- dsDesc.StencilWriteMask = gl_d3d11::ConvertStencilMask(dsState.stencilWritemask);
- dsDesc.FrontFace.StencilFailOp = gl_d3d11::ConvertStencilOp(dsState.stencilFail);
- dsDesc.FrontFace.StencilDepthFailOp = gl_d3d11::ConvertStencilOp(dsState.stencilPassDepthFail);
- dsDesc.FrontFace.StencilPassOp = gl_d3d11::ConvertStencilOp(dsState.stencilPassDepthPass);
- dsDesc.FrontFace.StencilFunc = gl_d3d11::ConvertComparison(dsState.stencilFunc);
- dsDesc.BackFace.StencilFailOp = gl_d3d11::ConvertStencilOp(dsState.stencilBackFail);
- dsDesc.BackFace.StencilDepthFailOp = gl_d3d11::ConvertStencilOp(dsState.stencilBackPassDepthFail);
- dsDesc.BackFace.StencilPassOp = gl_d3d11::ConvertStencilOp(dsState.stencilBackPassDepthPass);
- dsDesc.BackFace.StencilFunc = gl_d3d11::ConvertComparison(dsState.stencilBackFunc);
-
- ID3D11DepthStencilState *dx11DepthStencilState = NULL;
- HRESULT result = mDevice->CreateDepthStencilState(&dsDesc, &dx11DepthStencilState);
- if (FAILED(result) || !dx11DepthStencilState)
- {
- return gl::Error(GL_OUT_OF_MEMORY, "Unable to create a ID3D11DepthStencilState, HRESULT: 0x%X.", result);
- }
+ D3D11_DEPTH_STENCIL_DESC dsDesc = {0};
+ dsDesc.DepthEnable = glState.depthTest ? TRUE : FALSE;
+ dsDesc.DepthWriteMask = ConvertDepthMask(glState.depthMask);
+ dsDesc.DepthFunc = ConvertComparison(glState.depthFunc);
+ dsDesc.StencilEnable = glState.stencilTest ? TRUE : FALSE;
+ dsDesc.StencilReadMask = ConvertStencilMask(glState.stencilMask);
+ dsDesc.StencilWriteMask = ConvertStencilMask(glState.stencilWritemask);
+ dsDesc.FrontFace.StencilFailOp = ConvertStencilOp(glState.stencilFail);
+ dsDesc.FrontFace.StencilDepthFailOp = ConvertStencilOp(glState.stencilPassDepthFail);
+ dsDesc.FrontFace.StencilPassOp = ConvertStencilOp(glState.stencilPassDepthPass);
+ dsDesc.FrontFace.StencilFunc = ConvertComparison(glState.stencilFunc);
+ dsDesc.BackFace.StencilFailOp = ConvertStencilOp(glState.stencilBackFail);
+ dsDesc.BackFace.StencilDepthFailOp = ConvertStencilOp(glState.stencilBackPassDepthFail);
+ dsDesc.BackFace.StencilPassOp = ConvertStencilOp(glState.stencilBackPassDepthPass);
+ dsDesc.BackFace.StencilFunc = ConvertComparison(glState.stencilBackFunc);
+
+ ID3D11DepthStencilState *dx11DepthStencilState = NULL;
+ HRESULT result = mDevice->CreateDepthStencilState(&dsDesc, &dx11DepthStencilState);
+ if (FAILED(result) || !dx11DepthStencilState)
+ {
+ return gl::Error(GL_OUT_OF_MEMORY,
+ "Unable to create a ID3D11DepthStencilState, HRESULT: 0x%X.", result);
+ }
- mDepthStencilStateCache.insert(std::make_pair(dsState, std::make_pair(dx11DepthStencilState, mCounter++)));
+ mDepthStencilStateCache.insert(
+ std::make_pair(glState, std::make_pair(dx11DepthStencilState, mCounter++)));
- *outDSState = dx11DepthStencilState;
- return gl::Error(GL_NO_ERROR);
- }
+ *outDSState = dx11DepthStencilState;
+ return gl::Error(GL_NO_ERROR);
}
std::size_t RenderStateCache::hashSamplerState(const gl::SamplerState &samplerState)
@@ -416,7 +436,7 @@ gl::Error RenderStateCache::getSamplerState(const gl::SamplerState &samplerState
samplerDesc.AddressV = gl_d3d11::ConvertTextureWrap(samplerState.wrapT);
samplerDesc.AddressW = gl_d3d11::ConvertTextureWrap(samplerState.wrapR);
samplerDesc.MipLODBias = 0;
- samplerDesc.MaxAnisotropy = samplerState.maxAnisotropy;
+ samplerDesc.MaxAnisotropy = static_cast<UINT>(samplerState.maxAnisotropy);
samplerDesc.ComparisonFunc = gl_d3d11::ConvertComparison(samplerState.compareFunc);
samplerDesc.BorderColor[0] = 0.0f;
samplerDesc.BorderColor[1] = 0.0f;
@@ -425,7 +445,7 @@ gl::Error RenderStateCache::getSamplerState(const gl::SamplerState &samplerState
samplerDesc.MinLOD = samplerState.minLod;
samplerDesc.MaxLOD = samplerState.maxLod;
- if (mRenderer->getFeatureLevel() <= D3D_FEATURE_LEVEL_9_3)
+ if (mRenderer->getRenderer11DeviceCaps().featureLevel <= D3D_FEATURE_LEVEL_9_3)
{
// Check that maxLOD is nearly FLT_MAX (1000.0f is the default), since 9_3 doesn't support anything other than FLT_MAX.
// Note that Feature Level 9_* only supports GL ES 2.0, so the consumer of ANGLE can't modify the Max LOD themselves.
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/RenderStateCache.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/RenderStateCache.h
index 0099b94a04..82cb13903c 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/RenderStateCache.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/RenderStateCache.h
@@ -36,7 +36,10 @@ class RenderStateCache : angle::NonCopyable
gl::Error getBlendState(const gl::Framebuffer *framebuffer, const gl::BlendState &blendState, ID3D11BlendState **outBlendState);
gl::Error getRasterizerState(const gl::RasterizerState &rasterState, bool scissorEnabled, ID3D11RasterizerState **outRasterizerState);
- gl::Error getDepthStencilState(const gl::DepthStencilState &dsState, ID3D11DepthStencilState **outDSState);
+ gl::Error getDepthStencilState(const gl::DepthStencilState &dsState,
+ bool disableDepth,
+ bool disableStencil,
+ ID3D11DepthStencilState **outDSState);
gl::Error getSamplerState(const gl::SamplerState &samplerState, ID3D11SamplerState **outSamplerState);
private:
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/RenderTarget11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/RenderTarget11.cpp
index ecd9e13c90..cdfcacc287 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/RenderTarget11.cpp
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/RenderTarget11.cpp
@@ -8,10 +8,12 @@
// retained by Renderbuffers.
#include "libANGLE/renderer/d3d/d3d11/RenderTarget11.h"
+
+#include "libANGLE/renderer/d3d/d3d11/formatutils11.h"
#include "libANGLE/renderer/d3d/d3d11/Renderer11.h"
#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h"
#include "libANGLE/renderer/d3d/d3d11/SwapChain11.h"
-#include "libANGLE/renderer/d3d/d3d11/formatutils11.h"
+#include "libANGLE/renderer/d3d/d3d11/texture_format_table.h"
namespace rx
{
@@ -176,12 +178,6 @@ static unsigned int getDSVSubresourceIndex(ID3D11Resource *resource, ID3D11Depth
return D3D11CalcSubresource(mipSlice, arraySlice, mipLevels);
}
-RenderTarget11 *RenderTarget11::makeRenderTarget11(RenderTargetD3D *target)
-{
- ASSERT(HAS_DYNAMIC_TYPE(RenderTarget11*, target));
- return static_cast<RenderTarget11*>(target);
-}
-
TextureRenderTarget11::TextureRenderTarget11(ID3D11RenderTargetView *rtv, ID3D11Resource *resource, ID3D11ShaderResourceView *srv,
GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLsizei samples)
: mWidth(width),
@@ -352,7 +348,7 @@ GLsizei SurfaceRenderTarget11::getDepth() const
GLenum SurfaceRenderTarget11::getInternalFormat() const
{
- return (mDepth ? mSwapChain->GetDepthBufferInternalFormat() : mSwapChain->GetBackBufferInternalFormat());
+ return (mDepth ? mSwapChain->GetDepthBufferInternalFormat() : mSwapChain->GetRenderTargetInternalFormat());
}
GLsizei SurfaceRenderTarget11::getSamples() const
@@ -388,7 +384,7 @@ unsigned int SurfaceRenderTarget11::getSubresourceIndex() const
DXGI_FORMAT SurfaceRenderTarget11::getDXGIFormat() const
{
- return d3d11::GetTextureFormatInfo(getInternalFormat(), mRenderer->getFeatureLevel()).texFormat;
+ return d3d11::GetTextureFormatInfo(getInternalFormat(), mRenderer->getRenderer11DeviceCaps()).texFormat;
}
}
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/RenderTarget11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/RenderTarget11.h
index 4472a56175..d47b237c09 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/RenderTarget11.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/RenderTarget11.h
@@ -23,8 +23,6 @@ class RenderTarget11 : public RenderTargetD3D
RenderTarget11() { }
virtual ~RenderTarget11() { }
- static RenderTarget11 *makeRenderTarget11(RenderTargetD3D *renderTarget);
-
virtual ID3D11Resource *getTexture() const = 0;
virtual ID3D11RenderTargetView *getRenderTargetView() const = 0;
virtual ID3D11DepthStencilView *getDepthStencilView() const = 0;
@@ -33,9 +31,6 @@ class RenderTarget11 : public RenderTargetD3D
virtual unsigned int getSubresourceIndex() const = 0;
virtual DXGI_FORMAT getDXGIFormat() const = 0;
-
- private:
- D3D_FEATURE_LEVEL mFeatureLevel;
};
class TextureRenderTarget11 : public RenderTarget11
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp
index 223e2b019b..62badccefc 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp
@@ -8,47 +8,63 @@
#include "libANGLE/renderer/d3d/d3d11/Renderer11.h"
-#include "common/utilities.h"
+#include <EGL/eglext.h>
+#include <sstream>
+#if !defined(ANGLE_MINGW32_COMPAT) && WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP
+#include <VersionHelpers.h>
+#endif
+
#include "common/tls.h"
+#include "common/utilities.h"
#include "libANGLE/Buffer.h"
#include "libANGLE/Display.h"
+#include "libANGLE/formatutils.h"
#include "libANGLE/Framebuffer.h"
#include "libANGLE/FramebufferAttachment.h"
+#include "libANGLE/histogram_macros.h"
#include "libANGLE/Program.h"
-#include "libANGLE/State.h"
-#include "libANGLE/Surface.h"
-#include "libANGLE/formatutils.h"
#include "libANGLE/renderer/d3d/CompilerD3D.h"
-#include "libANGLE/renderer/d3d/FramebufferD3D.h"
-#include "libANGLE/renderer/d3d/IndexDataManager.h"
-#include "libANGLE/renderer/d3d/ProgramD3D.h"
-#include "libANGLE/renderer/d3d/RenderbufferD3D.h"
-#include "libANGLE/renderer/d3d/ShaderD3D.h"
-#include "libANGLE/renderer/d3d/SurfaceD3D.h"
-#include "libANGLE/renderer/d3d/TextureD3D.h"
-#include "libANGLE/renderer/d3d/TransformFeedbackD3D.h"
-#include "libANGLE/renderer/d3d/VertexDataManager.h"
#include "libANGLE/renderer/d3d/d3d11/Blit11.h"
#include "libANGLE/renderer/d3d/d3d11/Buffer11.h"
#include "libANGLE/renderer/d3d/d3d11/Clear11.h"
+#include "libANGLE/renderer/d3d/d3d11/dxgi_support_table.h"
#include "libANGLE/renderer/d3d/d3d11/Fence11.h"
+#include "libANGLE/renderer/d3d/d3d11/formatutils11.h"
#include "libANGLE/renderer/d3d/d3d11/Framebuffer11.h"
#include "libANGLE/renderer/d3d/d3d11/Image11.h"
#include "libANGLE/renderer/d3d/d3d11/IndexBuffer11.h"
#include "libANGLE/renderer/d3d/d3d11/PixelTransfer11.h"
#include "libANGLE/renderer/d3d/d3d11/Query11.h"
+#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h"
#include "libANGLE/renderer/d3d/d3d11/RenderTarget11.h"
#include "libANGLE/renderer/d3d/d3d11/ShaderExecutable11.h"
#include "libANGLE/renderer/d3d/d3d11/SwapChain11.h"
+#include "libANGLE/renderer/d3d/d3d11/texture_format_table.h"
#include "libANGLE/renderer/d3d/d3d11/TextureStorage11.h"
#include "libANGLE/renderer/d3d/d3d11/Trim11.h"
#include "libANGLE/renderer/d3d/d3d11/VertexArray11.h"
#include "libANGLE/renderer/d3d/d3d11/VertexBuffer11.h"
-#include "libANGLE/renderer/d3d/d3d11/formatutils11.h"
-#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h"
+#include "libANGLE/renderer/d3d/CompilerD3D.h"
+#include "libANGLE/renderer/d3d/DeviceD3D.h"
+#include "libANGLE/renderer/d3d/FramebufferD3D.h"
+#include "libANGLE/renderer/d3d/IndexDataManager.h"
+#include "libANGLE/renderer/d3d/ProgramD3D.h"
+#include "libANGLE/renderer/d3d/RenderbufferD3D.h"
+#include "libANGLE/renderer/d3d/ShaderD3D.h"
+#include "libANGLE/renderer/d3d/SurfaceD3D.h"
+#include "libANGLE/renderer/d3d/TextureD3D.h"
+#include "libANGLE/renderer/d3d/TransformFeedbackD3D.h"
+#include "libANGLE/renderer/d3d/VertexDataManager.h"
+#include "libANGLE/State.h"
+#include "libANGLE/Surface.h"
+#include "third_party/trace_event/trace_event.h"
-#include <sstream>
-#include <EGL/eglext.h>
+// Include the D3D9 debug annotator header for use by the desktop D3D11 renderer
+// because the D3D11 interface method ID3DUserDefinedAnnotation::GetStatus
+// doesn't work with the Graphics Diagnostics tools in Visual Studio 2013.
+#ifdef ANGLE_ENABLE_D3D9
+#include "libANGLE/renderer/d3d/d3d9/DebugAnnotator9.h"
+#endif
// Enable ANGLE_SKIP_DXGI_1_2_CHECK if there is not a possibility of using cross-process
// HWNDs or the Windows 7 Platform Update (KB2670838) is expected to be installed.
@@ -62,67 +78,6 @@
#define ANGLE_SUPPRESS_D3D11_HAZARD_WARNINGS 1
#endif
-#ifndef __d3d11sdklayers_h__
-#define D3D11_MESSAGE_CATEGORY UINT
-#define D3D11_MESSAGE_SEVERITY UINT
-#define D3D11_MESSAGE_ID UINT
-struct D3D11_MESSAGE;
-typedef struct D3D11_INFO_QUEUE_FILTER_DESC
-{
- UINT NumCategories;
- D3D11_MESSAGE_CATEGORY *pCategoryList;
- UINT NumSeverities;
- D3D11_MESSAGE_SEVERITY *pSeverityList;
- UINT NumIDs;
- D3D11_MESSAGE_ID *pIDList;
-} D3D11_INFO_QUEUE_FILTER_DESC;
-typedef struct D3D11_INFO_QUEUE_FILTER
-{
- D3D11_INFO_QUEUE_FILTER_DESC AllowList;
- D3D11_INFO_QUEUE_FILTER_DESC DenyList;
-} D3D11_INFO_QUEUE_FILTER;
-static const IID IID_ID3D11InfoQueue = { 0x6543dbb6, 0x1b48, 0x42f5, 0xab, 0x82, 0xe9, 0x7e, 0xc7, 0x43, 0x26, 0xf6 };
-MIDL_INTERFACE("6543dbb6-1b48-42f5-ab82-e97ec74326f6") ID3D11InfoQueue : public IUnknown
-{
-public:
- virtual HRESULT __stdcall SetMessageCountLimit(UINT64) = 0;
- virtual void __stdcall ClearStoredMessages() = 0;
- virtual HRESULT __stdcall GetMessage(UINT64, D3D11_MESSAGE *, SIZE_T *) = 0;
- virtual UINT64 __stdcall GetNumMessagesAllowedByStorageFilter() = 0;
- virtual UINT64 __stdcall GetNumMessagesDeniedByStorageFilter() = 0;
- virtual UINT64 __stdcall GetNumStoredMessages() = 0;
- virtual UINT64 __stdcall GetNumStoredMessagesAllowedByRetrievalFilter() = 0;
- virtual UINT64 __stdcall GetNumMessagesDiscardedByMessageCountLimit() = 0;
- virtual UINT64 __stdcall GetMessageCountLimit() = 0;
- virtual HRESULT __stdcall AddStorageFilterEntries(D3D11_INFO_QUEUE_FILTER *) = 0;
- virtual HRESULT __stdcall GetStorageFilter(D3D11_INFO_QUEUE_FILTER *, SIZE_T *) = 0;
- virtual void __stdcall ClearStorageFilter() = 0;
- virtual HRESULT __stdcall PushEmptyStorageFilter() = 0;
- virtual HRESULT __stdcall PushCopyOfStorageFilter() = 0;
- virtual HRESULT __stdcall PushStorageFilter(D3D11_INFO_QUEUE_FILTER *) = 0;
- virtual void __stdcall PopStorageFilter() = 0;
- virtual UINT __stdcall GetStorageFilterStackSize() = 0;
- virtual HRESULT __stdcall AddRetrievalFilterEntries(D3D11_INFO_QUEUE_FILTER *) = 0;
- virtual HRESULT __stdcall GetRetrievalFilter(D3D11_INFO_QUEUE_FILTER *, SIZE_T *) = 0;
- virtual void __stdcall ClearRetrievalFilter() = 0;
- virtual HRESULT __stdcall PushEmptyRetrievalFilter() = 0;
- virtual HRESULT __stdcall PushCopyOfRetrievalFilter() = 0;
- virtual HRESULT __stdcall PushRetrievalFilter(D3D11_INFO_QUEUE_FILTER *) = 0;
- virtual void __stdcall PopRetrievalFilter() = 0;
- virtual UINT __stdcall GetRetrievalFilterStackSize() = 0;
- virtual HRESULT __stdcall AddMessage(D3D11_MESSAGE_CATEGORY, D3D11_MESSAGE_SEVERITY, D3D11_MESSAGE_ID, LPCSTR) = 0;
- virtual HRESULT __stdcall AddApplicationMessage(D3D11_MESSAGE_SEVERITY, LPCSTR) = 0;
- virtual HRESULT __stdcall SetBreakOnCategory(D3D11_MESSAGE_CATEGORY, BOOL) = 0;
- virtual HRESULT __stdcall SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY, BOOL) = 0;
- virtual HRESULT __stdcall SetBreakOnID(D3D11_MESSAGE_ID, BOOL) = 0;
- virtual BOOL __stdcall GetBreakOnCategory(D3D11_MESSAGE_CATEGORY) = 0;
- virtual BOOL __stdcall GetBreakOnSeverity(D3D11_MESSAGE_SEVERITY) = 0;
- virtual BOOL __stdcall GetBreakOnID(D3D11_MESSAGE_ID) = 0;
- virtual void __stdcall SetMuteDebugOutput(BOOL) = 0;
- virtual BOOL __stdcall GetMuteDebugOutput() = 0;
-};
-#endif
-
namespace rx
{
@@ -134,107 +89,299 @@ enum
MAX_TEXTURE_IMAGE_UNITS_VTF_SM4 = 16
};
-// dirtyPointer is a special value that will make the comparison with any valid pointer fail and force the renderer to re-apply the state.
-static const uintptr_t DirtyPointer = static_cast<uintptr_t>(-1);
+#if defined(ANGLE_ENABLE_D3D11_1)
+void CalculateConstantBufferParams(GLintptr offset, GLsizeiptr size, UINT *outFirstConstant, UINT *outNumConstants)
+{
+ // The offset must be aligned to 256 bytes (should have been enforced by glBindBufferRange).
+ ASSERT(offset % 256 == 0);
+
+ // firstConstant and numConstants are expressed in constants of 16-bytes. Furthermore they must be a multiple of 16 constants.
+ *outFirstConstant = static_cast<UINT>(offset / 16);
+
+ // The GL size is not required to be aligned to a 256 bytes boundary.
+ // Round the size up to a 256 bytes boundary then express the results in constants of 16-bytes.
+ *outNumConstants = static_cast<UINT>(rx::roundUp(size, static_cast<GLsizeiptr>(256)) / 16);
-static bool ImageIndexConflictsWithSRV(const gl::ImageIndex *index, D3D11_SHADER_RESOURCE_VIEW_DESC desc)
+ // Since the size is rounded up, firstConstant + numConstants may be bigger than the actual size of the buffer.
+ // This behaviour is explictly allowed according to the documentation on ID3D11DeviceContext1::PSSetConstantBuffers1
+ // https://msdn.microsoft.com/en-us/library/windows/desktop/hh404649%28v=vs.85%29.aspx
+}
+#endif
+
+enum ANGLEFeatureLevel
{
- unsigned mipLevel = index->mipIndex;
- unsigned layerIndex = index->layerIndex;
- GLenum type = index->type;
+ ANGLE_FEATURE_LEVEL_INVALID,
+ ANGLE_FEATURE_LEVEL_9_3,
+ ANGLE_FEATURE_LEVEL_10_0,
+ ANGLE_FEATURE_LEVEL_10_1,
+ ANGLE_FEATURE_LEVEL_11_0,
+ ANGLE_FEATURE_LEVEL_11_1,
+ NUM_ANGLE_FEATURE_LEVELS
+};
- switch (desc.ViewDimension)
+ANGLEFeatureLevel GetANGLEFeatureLevel(D3D_FEATURE_LEVEL d3dFeatureLevel)
+{
+ switch (d3dFeatureLevel)
{
- case D3D11_SRV_DIMENSION_TEXTURE2D:
- {
- unsigned maxSrvMip = desc.Texture2D.MipLevels + desc.Texture2D.MostDetailedMip;
- maxSrvMip = (desc.Texture2D.MipLevels == -1) ? INT_MAX : maxSrvMip;
+ case D3D_FEATURE_LEVEL_9_3: return ANGLE_FEATURE_LEVEL_9_3;
+ case D3D_FEATURE_LEVEL_10_0: return ANGLE_FEATURE_LEVEL_10_0;
+ case D3D_FEATURE_LEVEL_10_1: return ANGLE_FEATURE_LEVEL_10_1;
+ case D3D_FEATURE_LEVEL_11_0: return ANGLE_FEATURE_LEVEL_11_0;
+ // Note: we don't ever request a 11_1 device, because this gives
+ // an E_INVALIDARG error on systems that don't have the platform update.
+ case D3D_FEATURE_LEVEL_11_1: return ANGLE_FEATURE_LEVEL_11_1;
+ default: return ANGLE_FEATURE_LEVEL_INVALID;
+ }
+}
- unsigned mipMin = index->mipIndex;
- unsigned mipMax = (layerIndex == -1) ? INT_MAX : layerIndex;
+void SetLineLoopIndices(GLuint *dest, size_t count)
+{
+ for (size_t i = 0; i < count; i++)
+ {
+ dest[i] = static_cast<GLuint>(i);
+ }
+ dest[count] = 0;
+}
- return type == GL_TEXTURE_2D && RangeUI(mipMin, mipMax).intersects(RangeUI(desc.Texture2D.MostDetailedMip, maxSrvMip));
- }
+template <typename T>
+void CopyLineLoopIndices(const GLvoid *indices, GLuint *dest, size_t count)
+{
+ const T *srcPtr = static_cast<const T *>(indices);
+ for (size_t i = 0; i < count; ++i)
+ {
+ dest[i] = static_cast<GLuint>(srcPtr[i]);
+ }
+ dest[count] = static_cast<GLuint>(srcPtr[0]);
+}
- case D3D11_SRV_DIMENSION_TEXTURE2DARRAY:
- {
- unsigned maxSrvMip = desc.Texture2DArray.MipLevels + desc.Texture2DArray.MostDetailedMip;
- maxSrvMip = (desc.Texture2DArray.MipLevels == -1) ? INT_MAX : maxSrvMip;
+void SetTriangleFanIndices(GLuint *destPtr, size_t numTris)
+{
+ for (size_t i = 0; i < numTris; i++)
+ {
+ destPtr[i * 3 + 0] = 0;
+ destPtr[i * 3 + 1] = static_cast<GLuint>(i) + 1;
+ destPtr[i * 3 + 2] = static_cast<GLuint>(i) + 2;
+ }
+}
+
+template <typename T>
+void CopyLineLoopIndicesWithRestart(const GLvoid *indices,
+ size_t count,
+ GLenum indexType,
+ std::vector<GLuint> *bufferOut)
+{
+ GLuint restartIndex = gl::GetPrimitiveRestartIndex(indexType);
+ GLuint d3dRestartIndex = static_cast<GLuint>(d3d11::GetPrimitiveRestartIndex());
+ const T *srcPtr = static_cast<const T *>(indices);
+ Optional<GLuint> currentLoopStart;
- unsigned maxSlice = desc.Texture2DArray.FirstArraySlice + desc.Texture2DArray.ArraySize;
+ bufferOut->clear();
- // Cube maps can be mapped to Texture2DArray SRVs
- return (type == GL_TEXTURE_2D_ARRAY || gl::IsCubeMapTextureTarget(type)) &&
- desc.Texture2DArray.MostDetailedMip <= mipLevel && mipLevel < maxSrvMip &&
- desc.Texture2DArray.FirstArraySlice <= layerIndex && layerIndex < maxSlice;
- }
+ for (size_t indexIdx = 0; indexIdx < count; ++indexIdx)
+ {
+ GLuint value = static_cast<GLuint>(srcPtr[indexIdx]);
- case D3D11_SRV_DIMENSION_TEXTURECUBE:
+ if (value == restartIndex)
{
- unsigned maxSrvMip = desc.TextureCube.MipLevels + desc.TextureCube.MostDetailedMip;
- maxSrvMip = (desc.TextureCube.MipLevels == -1) ? INT_MAX : maxSrvMip;
-
- return gl::IsCubeMapTextureTarget(type) &&
- desc.TextureCube.MostDetailedMip <= mipLevel && mipLevel < maxSrvMip;
+ if (currentLoopStart.valid())
+ {
+ bufferOut->push_back(currentLoopStart.value());
+ bufferOut->push_back(d3dRestartIndex);
+ currentLoopStart.reset();
+ }
}
-
- case D3D11_SRV_DIMENSION_TEXTURE3D:
+ else
{
- unsigned maxSrvMip = desc.Texture3D.MipLevels + desc.Texture3D.MostDetailedMip;
- maxSrvMip = (desc.Texture3D.MipLevels == -1) ? INT_MAX : maxSrvMip;
-
- return type == GL_TEXTURE_3D &&
- desc.Texture3D.MostDetailedMip <= mipLevel && mipLevel < maxSrvMip;
+ bufferOut->push_back(value);
+ if (!currentLoopStart.valid())
+ {
+ currentLoopStart = value;
+ }
}
- default:
- // We only handle the cases corresponding to valid image indexes
- UNIMPLEMENTED();
}
- return false;
+ if (currentLoopStart.valid())
+ {
+ bufferOut->push_back(currentLoopStart.value());
+ }
}
-// Does *not* increment the resource ref count!!
-ID3D11Resource *GetViewResource(ID3D11View *view)
+void GetLineLoopIndices(const GLvoid *indices,
+ GLenum indexType,
+ GLuint count,
+ bool usePrimitiveRestartFixedIndex,
+ std::vector<GLuint> *bufferOut)
{
- ID3D11Resource *resource = NULL;
- ASSERT(view);
- view->GetResource(&resource);
- resource->Release();
- return resource;
+ if (indexType != GL_NONE && usePrimitiveRestartFixedIndex)
+ {
+ switch (indexType)
+ {
+ case GL_UNSIGNED_BYTE:
+ CopyLineLoopIndicesWithRestart<GLubyte>(indices, count, indexType, bufferOut);
+ break;
+ case GL_UNSIGNED_SHORT:
+ CopyLineLoopIndicesWithRestart<GLushort>(indices, count, indexType, bufferOut);
+ break;
+ case GL_UNSIGNED_INT:
+ CopyLineLoopIndicesWithRestart<GLuint>(indices, count, indexType, bufferOut);
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+ return;
+ }
+
+ // For non-primitive-restart draws, the index count is static.
+ bufferOut->resize(static_cast<size_t>(count) + 1);
+
+ switch (indexType)
+ {
+ // Non-indexed draw
+ case GL_NONE:
+ SetLineLoopIndices(&(*bufferOut)[0], count);
+ break;
+ case GL_UNSIGNED_BYTE:
+ CopyLineLoopIndices<GLubyte>(indices, &(*bufferOut)[0], count);
+ break;
+ case GL_UNSIGNED_SHORT:
+ CopyLineLoopIndices<GLushort>(indices, &(*bufferOut)[0], count);
+ break;
+ case GL_UNSIGNED_INT:
+ CopyLineLoopIndices<GLuint>(indices, &(*bufferOut)[0], count);
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
}
-void CalculateConstantBufferParams(GLintptr offset, GLsizeiptr size, UINT *outFirstConstant, UINT *outNumConstants)
+template <typename T>
+void CopyTriangleFanIndices(const GLvoid *indices, GLuint *destPtr, size_t numTris)
{
- // The offset must be aligned to 256 bytes (should have been enforced by glBindBufferRange).
- ASSERT(offset % 256 == 0);
+ const T *srcPtr = static_cast<const T *>(indices);
- // firstConstant and numConstants are expressed in constants of 16-bytes. Furthermore they must be a multiple of 16 constants.
- *outFirstConstant = offset / 16;
+ for (size_t i = 0; i < numTris; i++)
+ {
+ destPtr[i * 3 + 0] = static_cast<GLuint>(srcPtr[0]);
+ destPtr[i * 3 + 1] = static_cast<GLuint>(srcPtr[i + 1]);
+ destPtr[i * 3 + 2] = static_cast<GLuint>(srcPtr[i + 2]);
+ }
+}
- // The GL size is not required to be aligned to a 256 bytes boundary.
- // Round the size up to a 256 bytes boundary then express the results in constants of 16-bytes.
- *outNumConstants = rx::roundUp(size, static_cast<GLsizeiptr>(256)) / 16;
+template <typename T>
+void CopyTriangleFanIndicesWithRestart(const GLvoid *indices,
+ GLuint indexCount,
+ GLenum indexType,
+ std::vector<GLuint> *bufferOut)
+{
+ GLuint restartIndex = gl::GetPrimitiveRestartIndex(indexType);
+ GLuint d3dRestartIndex = gl::GetPrimitiveRestartIndex(GL_UNSIGNED_INT);
+ const T *srcPtr = static_cast<const T *>(indices);
+ Optional<GLuint> vertexA;
+ Optional<GLuint> vertexB;
- // Since the size is rounded up, firstConstant + numConstants may be bigger than the actual size of the buffer.
- // This behaviour is explictly allowed according to the documentation on ID3D11DeviceContext1::PSSetConstantBuffers1
- // https://msdn.microsoft.com/en-us/library/windows/desktop/hh404649%28v=vs.85%29.aspx
+ bufferOut->clear();
+
+ for (size_t indexIdx = 0; indexIdx < indexCount; ++indexIdx)
+ {
+ GLuint value = static_cast<GLuint>(srcPtr[indexIdx]);
+
+ if (value == restartIndex)
+ {
+ bufferOut->push_back(d3dRestartIndex);
+ vertexA.reset();
+ vertexB.reset();
+ }
+ else
+ {
+ if (!vertexA.valid())
+ {
+ vertexA = value;
+ }
+ else if (!vertexB.valid())
+ {
+ vertexB = value;
+ }
+ else
+ {
+ bufferOut->push_back(vertexA.value());
+ bufferOut->push_back(vertexB.value());
+ bufferOut->push_back(value);
+ vertexB = value;
+ }
+ }
+ }
}
+void GetTriFanIndices(const GLvoid *indices,
+ GLenum indexType,
+ GLuint count,
+ bool usePrimitiveRestartFixedIndex,
+ std::vector<GLuint> *bufferOut)
+{
+ if (indexType != GL_NONE && usePrimitiveRestartFixedIndex)
+ {
+ switch (indexType)
+ {
+ case GL_UNSIGNED_BYTE:
+ CopyTriangleFanIndicesWithRestart<GLubyte>(indices, count, indexType, bufferOut);
+ break;
+ case GL_UNSIGNED_SHORT:
+ CopyTriangleFanIndicesWithRestart<GLushort>(indices, count, indexType, bufferOut);
+ break;
+ case GL_UNSIGNED_INT:
+ CopyTriangleFanIndicesWithRestart<GLuint>(indices, count, indexType, bufferOut);
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+ return;
+ }
+
+ // For non-primitive-restart draws, the index count is static.
+ GLuint numTris = count - 2;
+ bufferOut->resize(numTris * 3);
+
+ switch (indexType)
+ {
+ // Non-indexed draw
+ case GL_NONE:
+ SetTriangleFanIndices(&(*bufferOut)[0], numTris);
+ break;
+ case GL_UNSIGNED_BYTE:
+ CopyTriangleFanIndices<GLubyte>(indices, &(*bufferOut)[0], numTris);
+ break;
+ case GL_UNSIGNED_SHORT:
+ CopyTriangleFanIndices<GLushort>(indices, &(*bufferOut)[0], numTris);
+ break;
+ case GL_UNSIGNED_INT:
+ CopyTriangleFanIndices<GLuint>(indices, &(*bufferOut)[0], numTris);
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
}
+} // anonymous namespace
+
Renderer11::Renderer11(egl::Display *display)
: RendererD3D(display),
- mStateCache(this)
+ mStateCache(this),
+ mStateManager(this),
+ mLastHistogramUpdateTime(ANGLEPlatformCurrent()->monotonicallyIncreasingTime())
+#if !defined(ANGLE_MINGW32_COMPAT)
+ ,mDebug(nullptr)
+#endif
{
- // Initialize global annotator
- gl::InitializeDebugAnnotations(&mAnnotator);
-
mVertexDataManager = NULL;
mIndexDataManager = NULL;
mLineLoopIB = NULL;
mTriangleFanIB = NULL;
+ mAppliedIBChanged = false;
mBlit = NULL;
mPixelTransfer = NULL;
@@ -245,10 +392,18 @@ Renderer11::Renderer11(egl::Display *display)
mSyncQuery = NULL;
- mSupportsConstantBufferOffsets = false;
+ mRenderer11DeviceCaps.supportsClearView = false;
+ mRenderer11DeviceCaps.supportsConstantBufferOffsets = false;
+ mRenderer11DeviceCaps.supportsDXGI1_2 = false;
+ mRenderer11DeviceCaps.B5G6R5support = 0;
+ mRenderer11DeviceCaps.B4G4R4A4support = 0;
+ mRenderer11DeviceCaps.B5G5R5A1support = 0;
mD3d11Module = NULL;
mDxgiModule = NULL;
+ mDCompModule = NULL;
+ mCreatedWithDeviceEXT = false;
+ mEGLDevice = nullptr;
mDevice = NULL;
mDeviceContext = NULL;
@@ -265,89 +420,105 @@ Renderer11::Renderer11(egl::Display *display)
mAppliedNumXFBBindings = static_cast<size_t>(-1);
- const auto &attributes = mDisplay->getAttributeMap();
-
- EGLint requestedMajorVersion = attributes.get(EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE, EGL_DONT_CARE);
- EGLint requestedMinorVersion = attributes.get(EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE, EGL_DONT_CARE);
+ ZeroMemory(&mAdapterDescription, sizeof(mAdapterDescription));
- if (requestedMajorVersion == EGL_DONT_CARE || requestedMajorVersion >= 11)
+ if (mDisplay->getPlatform() == EGL_PLATFORM_ANGLE_ANGLE)
{
- if (requestedMinorVersion == EGL_DONT_CARE || requestedMinorVersion >= 0)
- {
- mAvailableFeatureLevels.push_back(D3D_FEATURE_LEVEL_11_0);
- }
- }
+ const auto &attributes = mDisplay->getAttributeMap();
- if (requestedMajorVersion == EGL_DONT_CARE || requestedMajorVersion >= 10)
- {
- if (requestedMinorVersion == EGL_DONT_CARE || requestedMinorVersion >= 1)
+ EGLint requestedMajorVersion =
+ attributes.get(EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE, EGL_DONT_CARE);
+ EGLint requestedMinorVersion =
+ attributes.get(EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE, EGL_DONT_CARE);
+
+ if (requestedMajorVersion == EGL_DONT_CARE || requestedMajorVersion >= 11)
{
- mAvailableFeatureLevels.push_back(D3D_FEATURE_LEVEL_10_1);
+ if (requestedMinorVersion == EGL_DONT_CARE || requestedMinorVersion >= 0)
+ {
+ mAvailableFeatureLevels.push_back(D3D_FEATURE_LEVEL_11_0);
+ }
}
- if (requestedMinorVersion == EGL_DONT_CARE || requestedMinorVersion >= 0)
+
+ if (requestedMajorVersion == EGL_DONT_CARE || requestedMajorVersion >= 10)
{
- mAvailableFeatureLevels.push_back(D3D_FEATURE_LEVEL_10_0);
+ if (requestedMinorVersion == EGL_DONT_CARE || requestedMinorVersion >= 1)
+ {
+ mAvailableFeatureLevels.push_back(D3D_FEATURE_LEVEL_10_1);
+ }
+ if (requestedMinorVersion == EGL_DONT_CARE || requestedMinorVersion >= 0)
+ {
+ mAvailableFeatureLevels.push_back(D3D_FEATURE_LEVEL_10_0);
+ }
}
- }
#if defined(ANGLE_ENABLE_WINDOWS_STORE)
- if (requestedMajorVersion == EGL_DONT_CARE || requestedMajorVersion >= 9)
+ if (requestedMajorVersion == EGL_DONT_CARE || requestedMajorVersion >= 9)
#else
- if (requestedMajorVersion == 9 && requestedMinorVersion == 3)
+ if (requestedMajorVersion == 9 && requestedMinorVersion == 3)
#endif
- {
- if (requestedMinorVersion == EGL_DONT_CARE || requestedMinorVersion >= 3)
{
- mAvailableFeatureLevels.push_back(D3D_FEATURE_LEVEL_9_3);
- }
+ if (requestedMinorVersion == EGL_DONT_CARE || requestedMinorVersion >= 3)
+ {
+ mAvailableFeatureLevels.push_back(D3D_FEATURE_LEVEL_9_3);
+ }
#if defined(ANGLE_ENABLE_WINDOWS_STORE)
- if (requestedMinorVersion == EGL_DONT_CARE || requestedMinorVersion >= 2)
- {
- mAvailableFeatureLevels.push_back(D3D_FEATURE_LEVEL_9_2);
+ if (requestedMinorVersion == EGL_DONT_CARE || requestedMinorVersion >= 2)
+ {
+ mAvailableFeatureLevels.push_back(D3D_FEATURE_LEVEL_9_2);
+ }
+ if (requestedMinorVersion == EGL_DONT_CARE || requestedMinorVersion >= 1)
+ {
+ mAvailableFeatureLevels.push_back(D3D_FEATURE_LEVEL_9_1);
+ }
+#endif
}
- if (requestedMinorVersion == EGL_DONT_CARE || requestedMinorVersion >= 1)
+
+ EGLint requestedDeviceType = attributes.get(EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE,
+ EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE);
+ switch (requestedDeviceType)
{
- mAvailableFeatureLevels.push_back(D3D_FEATURE_LEVEL_9_1);
- }
-#endif
- }
+ case EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE:
+ mRequestedDriverType = D3D_DRIVER_TYPE_HARDWARE;
+ break;
- EGLint requestedDeviceType = attributes.get(EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE,
- EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE);
- switch (requestedDeviceType)
- {
- case EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE:
- mDriverType = D3D_DRIVER_TYPE_HARDWARE;
- break;
+ case EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE:
+ mRequestedDriverType = D3D_DRIVER_TYPE_WARP;
+ break;
- case EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE:
- mDriverType = D3D_DRIVER_TYPE_WARP;
- break;
+ case EGL_PLATFORM_ANGLE_DEVICE_TYPE_REFERENCE_ANGLE:
+ mRequestedDriverType = D3D_DRIVER_TYPE_REFERENCE;
+ break;
- case EGL_PLATFORM_ANGLE_DEVICE_TYPE_REFERENCE_ANGLE:
- mDriverType = D3D_DRIVER_TYPE_REFERENCE;
- break;
+ case EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE:
+ mRequestedDriverType = D3D_DRIVER_TYPE_NULL;
+ break;
- case EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE:
- mDriverType = D3D_DRIVER_TYPE_NULL;
- break;
+ default:
+ UNREACHABLE();
+ }
- default:
- UNREACHABLE();
+ const EGLenum presentPath = attributes.get(EGL_EXPERIMENTAL_PRESENT_PATH_ANGLE,
+ EGL_EXPERIMENTAL_PRESENT_PATH_COPY_ANGLE);
+ mPresentPathFastEnabled = (presentPath == EGL_EXPERIMENTAL_PRESENT_PATH_FAST_ANGLE);
}
-}
+ else if (display->getPlatform() == EGL_PLATFORM_DEVICE_EXT)
+ {
+ mEGLDevice = GetImplAs<DeviceD3D>(display->getDevice());
+ ASSERT(mEGLDevice != nullptr);
+ mCreatedWithDeviceEXT = true;
-Renderer11::~Renderer11()
-{
- release();
+ // Also set EGL_PLATFORM_ANGLE_ANGLE variables, in case they're used elsewhere in ANGLE
+ // mAvailableFeatureLevels defaults to empty
+ mRequestedDriverType = D3D_DRIVER_TYPE_UNKNOWN;
+ mPresentPathFastEnabled = false;
+ }
- gl::UninitializeDebugAnnotations();
+ initializeDebugAnnotator();
}
-Renderer11 *Renderer11::makeRenderer11(Renderer *renderer)
+Renderer11::~Renderer11()
{
- ASSERT(HAS_DYNAMIC_TYPE(Renderer11*, renderer));
- return static_cast<Renderer11*>(renderer);
+ release();
}
#ifndef __d3d11_1_h__
@@ -356,209 +527,268 @@ Renderer11 *Renderer11::makeRenderer11(Renderer *renderer)
egl::Error Renderer11::initialize()
{
- if (!mCompiler.initialize())
+ HRESULT result = S_OK;
+
+ egl::Error error = initializeD3DDevice();
+ if (error.isError())
{
- return egl::Error(EGL_NOT_INITIALIZED,
- D3D11_INIT_COMPILER_ERROR,
- "Failed to initialize compiler.");
+ return error;
}
#if !defined(ANGLE_ENABLE_WINDOWS_STORE)
- mDxgiModule = LoadLibrary(TEXT("dxgi.dll"));
- mD3d11Module = LoadLibrary(TEXT("d3d11.dll"));
-
- if (mD3d11Module == NULL || mDxgiModule == NULL)
+#if !ANGLE_SKIP_DXGI_1_2_CHECK
{
- return egl::Error(EGL_NOT_INITIALIZED,
- D3D11_INIT_MISSING_DEP,
- "Could not load D3D11 or DXGI library.");
- }
-
- // create the D3D11 device
- ASSERT(mDevice == NULL);
- PFN_D3D11_CREATE_DEVICE D3D11CreateDevice = (PFN_D3D11_CREATE_DEVICE)GetProcAddress(mD3d11Module, "D3D11CreateDevice");
+ TRACE_EVENT0("gpu.angle", "Renderer11::initialize (DXGICheck)");
+ // In order to create a swap chain for an HWND owned by another process, DXGI 1.2 is required.
+ // The easiest way to check is to query for a IDXGIDevice2.
+ bool requireDXGI1_2 = false;
+ HWND hwnd = WindowFromDC(mDisplay->getNativeDisplayId());
+ if (hwnd)
+ {
+ DWORD currentProcessId = GetCurrentProcessId();
+ DWORD wndProcessId;
+ GetWindowThreadProcessId(hwnd, &wndProcessId);
+ requireDXGI1_2 = (currentProcessId != wndProcessId);
+ }
+ else
+ {
+ requireDXGI1_2 = true;
+ }
- if (D3D11CreateDevice == NULL)
- {
- return egl::Error(EGL_NOT_INITIALIZED,
- D3D11_INIT_MISSING_DEP,
- "Could not retrieve D3D11CreateDevice address.");
+ if (requireDXGI1_2)
+ {
+ IDXGIDevice2 *dxgiDevice2 = NULL;
+ result = mDevice->QueryInterface(__uuidof(IDXGIDevice2), (void**)&dxgiDevice2);
+ if (FAILED(result))
+ {
+ return egl::Error(EGL_NOT_INITIALIZED,
+ D3D11_INIT_INCOMPATIBLE_DXGI,
+ "DXGI 1.2 required to present to HWNDs owned by another process.");
+ }
+ SafeRelease(dxgiDevice2);
+ }
}
#endif
+#endif
- HRESULT result = S_OK;
-#ifdef _DEBUG
- result = D3D11CreateDevice(NULL,
- mDriverType,
- NULL,
- D3D11_CREATE_DEVICE_DEBUG,
- mAvailableFeatureLevels.data(),
- mAvailableFeatureLevels.size(),
- D3D11_SDK_VERSION,
- &mDevice,
- &mFeatureLevel,
- &mDeviceContext);
-
- if (!mDevice || FAILED(result))
{
- ERR("Failed creating Debug D3D11 device - falling back to release runtime.\n");
- }
-
- if (!mDevice || FAILED(result))
+ TRACE_EVENT0("gpu.angle", "Renderer11::initialize (ComQueries)");
+ // Cast the DeviceContext to a DeviceContext1.
+ // This could fail on Windows 7 without the Platform Update.
+ // Don't error in this case- just don't use mDeviceContext1.
+#if defined(ANGLE_ENABLE_D3D11_1)
+ mDeviceContext1 = d3d11::DynamicCastComObject<ID3D11DeviceContext1>(mDeviceContext);
#endif
- {
- result = D3D11CreateDevice(NULL,
- mDriverType,
- NULL,
- 0,
- mAvailableFeatureLevels.data(),
- mAvailableFeatureLevels.size(),
- D3D11_SDK_VERSION,
- &mDevice,
- &mFeatureLevel,
- &mDeviceContext);
- if (result == E_INVALIDARG)
+ IDXGIDevice *dxgiDevice = NULL;
+ result = mDevice->QueryInterface(__uuidof(IDXGIDevice), (void**)&dxgiDevice);
+
+ if (FAILED(result))
{
- // Cleanup done by destructor through glDestroyRenderer
return egl::Error(EGL_NOT_INITIALIZED,
- D3D11_INIT_CREATEDEVICE_INVALIDARG,
- "Could not create D3D11 device.");
+ D3D11_INIT_OTHER_ERROR,
+ "Could not query DXGI device.");
}
- if (!mDevice || FAILED(result))
+ result = dxgiDevice->GetParent(__uuidof(IDXGIAdapter), (void**)&mDxgiAdapter);
+
+ if (FAILED(result))
{
- // Cleanup done by destructor through glDestroyRenderer
return egl::Error(EGL_NOT_INITIALIZED,
- D3D11_INIT_CREATEDEVICE_ERROR,
- "Could not create D3D11 device.");
+ D3D11_INIT_OTHER_ERROR,
+ "Could not retrieve DXGI adapter");
}
- }
-#if !defined(ANGLE_ENABLE_WINDOWS_STORE)
-#if !ANGLE_SKIP_DXGI_1_2_CHECK
- // In order to create a swap chain for an HWND owned by another process, DXGI 1.2 is required.
- // The easiest way to check is to query for a IDXGIDevice2.
- bool requireDXGI1_2 = false;
- HWND hwnd = WindowFromDC(mDisplay->getNativeDisplayId());
- if (hwnd)
- {
- DWORD currentProcessId = GetCurrentProcessId();
- DWORD wndProcessId;
- GetWindowThreadProcessId(hwnd, &wndProcessId);
- requireDXGI1_2 = (currentProcessId != wndProcessId);
- }
- else
- {
- requireDXGI1_2 = true;
- }
+ SafeRelease(dxgiDevice);
- if (requireDXGI1_2)
- {
- IDXGIDevice2 *dxgiDevice2 = NULL;
- result = mDevice->QueryInterface(__uuidof(IDXGIDevice2), (void**)&dxgiDevice2);
- if (FAILED(result))
+#if defined(ANGLE_ENABLE_D3D11_1)
+ IDXGIAdapter2 *dxgiAdapter2 = d3d11::DynamicCastComObject<IDXGIAdapter2>(mDxgiAdapter);
+
+ // On D3D_FEATURE_LEVEL_9_*, IDXGIAdapter::GetDesc returns "Software Adapter" for the description string.
+ // If DXGI1.2 is available then IDXGIAdapter2::GetDesc2 can be used to get the actual hardware values.
+ if (mRenderer11DeviceCaps.featureLevel <= D3D_FEATURE_LEVEL_9_3 && dxgiAdapter2 != NULL)
{
- return egl::Error(EGL_NOT_INITIALIZED,
- D3D11_INIT_INCOMPATIBLE_DXGI,
- "DXGI 1.2 required to present to HWNDs owned by another process.");
+ DXGI_ADAPTER_DESC2 adapterDesc2 = {};
+ result = dxgiAdapter2->GetDesc2(&adapterDesc2);
+ if (SUCCEEDED(result))
+ {
+ // Copy the contents of the DXGI_ADAPTER_DESC2 into mAdapterDescription (a DXGI_ADAPTER_DESC).
+ memcpy(mAdapterDescription.Description, adapterDesc2.Description, sizeof(mAdapterDescription.Description));
+ mAdapterDescription.VendorId = adapterDesc2.VendorId;
+ mAdapterDescription.DeviceId = adapterDesc2.DeviceId;
+ mAdapterDescription.SubSysId = adapterDesc2.SubSysId;
+ mAdapterDescription.Revision = adapterDesc2.Revision;
+ mAdapterDescription.DedicatedVideoMemory = adapterDesc2.DedicatedVideoMemory;
+ mAdapterDescription.DedicatedSystemMemory = adapterDesc2.DedicatedSystemMemory;
+ mAdapterDescription.SharedSystemMemory = adapterDesc2.SharedSystemMemory;
+ mAdapterDescription.AdapterLuid = adapterDesc2.AdapterLuid;
+ }
}
- SafeRelease(dxgiDevice2);
- }
-#endif
+ else
#endif
+ {
+ result = mDxgiAdapter->GetDesc(&mAdapterDescription);
+ }
- // Cast the DeviceContext to a DeviceContext1.
- // This could fail on Windows 7 without the Platform Update.
- // Don't error in this case- just don't use mDeviceContext1.
#if defined(ANGLE_ENABLE_D3D11_1)
- mDeviceContext1 = d3d11::DynamicCastComObject<ID3D11DeviceContext1>(mDeviceContext);
+ SafeRelease(dxgiAdapter2);
#endif
- IDXGIDevice *dxgiDevice = NULL;
- result = mDevice->QueryInterface(__uuidof(IDXGIDevice), (void**)&dxgiDevice);
+ if (FAILED(result))
+ {
+ return egl::Error(EGL_NOT_INITIALIZED,
+ D3D11_INIT_OTHER_ERROR,
+ "Could not read DXGI adaptor description.");
+ }
- if (FAILED(result))
- {
- return egl::Error(EGL_NOT_INITIALIZED,
- D3D11_INIT_OTHER_ERROR,
- "Could not query DXGI device.");
- }
+ memset(mDescription, 0, sizeof(mDescription));
+ wcstombs(mDescription, mAdapterDescription.Description, sizeof(mDescription) - 1);
- result = dxgiDevice->GetParent(__uuidof(IDXGIAdapter), (void**)&mDxgiAdapter);
+ result = mDxgiAdapter->GetParent(__uuidof(IDXGIFactory), (void**)&mDxgiFactory);
- if (FAILED(result))
- {
- return egl::Error(EGL_NOT_INITIALIZED,
- D3D11_INIT_OTHER_ERROR,
- "Could not retrieve DXGI adapter");
+ if (!mDxgiFactory || FAILED(result))
+ {
+ return egl::Error(EGL_NOT_INITIALIZED,
+ D3D11_INIT_OTHER_ERROR,
+ "Could not create DXGI factory.");
+ }
}
- SafeRelease(dxgiDevice);
+#if !defined(ANGLE_MINGW32_COMPAT)
+ // Disable some spurious D3D11 debug warnings to prevent them from flooding the output log
+#if defined(ANGLE_SUPPRESS_D3D11_HAZARD_WARNINGS) && defined(_DEBUG)
+ {
+ TRACE_EVENT0("gpu.angle", "Renderer11::initialize (HideWarnings)");
+ ID3D11InfoQueue *infoQueue;
+ result = mDevice->QueryInterface(__uuidof(ID3D11InfoQueue), (void **)&infoQueue);
-#if defined(ANGLE_ENABLE_D3D11_1)
- IDXGIAdapter2 *dxgiAdapter2 = d3d11::DynamicCastComObject<IDXGIAdapter2>(mDxgiAdapter);
+ if (SUCCEEDED(result))
+ {
+ D3D11_MESSAGE_ID hideMessages[] =
+ {
+ D3D11_MESSAGE_ID_DEVICE_DRAW_RENDERTARGETVIEW_NOT_SET
+ };
- // On D3D_FEATURE_LEVEL_9_*, IDXGIAdapter::GetDesc returns "Software Adapter" for the description string.
- // If DXGI1.2 is available then IDXGIAdapter2::GetDesc2 can be used to get the actual hardware values.
- if (mFeatureLevel <= D3D_FEATURE_LEVEL_9_3 && dxgiAdapter2 != NULL)
- {
- DXGI_ADAPTER_DESC2 adapterDesc2 = {0};
- dxgiAdapter2->GetDesc2(&adapterDesc2);
+ D3D11_INFO_QUEUE_FILTER filter = {};
+ filter.DenyList.NumIDs = static_cast<unsigned int>(ArraySize(hideMessages));
+ filter.DenyList.pIDList = hideMessages;
- // Copy the contents of the DXGI_ADAPTER_DESC2 into mAdapterDescription (a DXGI_ADAPTER_DESC).
- memcpy(mAdapterDescription.Description, adapterDesc2.Description, sizeof(mAdapterDescription.Description));
- mAdapterDescription.VendorId = adapterDesc2.VendorId;
- mAdapterDescription.DeviceId = adapterDesc2.DeviceId;
- mAdapterDescription.SubSysId = adapterDesc2.SubSysId;
- mAdapterDescription.Revision = adapterDesc2.Revision;
- mAdapterDescription.DedicatedVideoMemory = adapterDesc2.DedicatedVideoMemory;
- mAdapterDescription.DedicatedSystemMemory = adapterDesc2.DedicatedSystemMemory;
- mAdapterDescription.SharedSystemMemory = adapterDesc2.SharedSystemMemory;
- mAdapterDescription.AdapterLuid = adapterDesc2.AdapterLuid;
- }
- else
- {
- mDxgiAdapter->GetDesc(&mAdapterDescription);
+ infoQueue->AddStorageFilterEntries(&filter);
+ SafeRelease(infoQueue);
+ }
}
+#endif
- SafeRelease(dxgiAdapter2);
+#if !defined(NDEBUG)
+ mDebug = d3d11::DynamicCastComObject<ID3D11Debug>(mDevice);
#endif
+#endif // !ANGLE_MINGW32_COMPAT
- memset(mDescription, 0, sizeof(mDescription));
- wcstombs(mDescription, mAdapterDescription.Description, sizeof(mDescription) - 1);
+ initializeDevice();
+
+ return egl::Error(EGL_SUCCESS);
+}
- result = mDxgiAdapter->GetParent(__uuidof(IDXGIFactory), (void**)&mDxgiFactory);
+egl::Error Renderer11::initializeD3DDevice()
+{
+ HRESULT result = S_OK;
- if (!mDxgiFactory || FAILED(result))
+ if (!mCreatedWithDeviceEXT)
{
- return egl::Error(EGL_NOT_INITIALIZED,
- D3D11_INIT_OTHER_ERROR,
- "Could not create DXGI factory.");
- }
+#if !defined(ANGLE_ENABLE_WINDOWS_STORE)
+ PFN_D3D11_CREATE_DEVICE D3D11CreateDevice = nullptr;
+ {
+ SCOPED_ANGLE_HISTOGRAM_TIMER("GPU.ANGLE.Renderer11InitializeDLLsMS");
+ TRACE_EVENT0("gpu.angle", "Renderer11::initialize (Load DLLs)");
+ mDxgiModule = LoadLibrary(TEXT("dxgi.dll"));
+ mD3d11Module = LoadLibrary(TEXT("d3d11.dll"));
+ mDCompModule = LoadLibrary(TEXT("dcomp.dll"));
- // Disable some spurious D3D11 debug warnings to prevent them from flooding the output log
-#if defined(ANGLE_SUPPRESS_D3D11_HAZARD_WARNINGS) && defined(_DEBUG)
- ID3D11InfoQueue *infoQueue;
- result = mDevice->QueryInterface(IID_ID3D11InfoQueue, (void **)&infoQueue);
+ if (mD3d11Module == nullptr || mDxgiModule == nullptr)
+ {
+ return egl::Error(EGL_NOT_INITIALIZED, D3D11_INIT_MISSING_DEP,
+ "Could not load D3D11 or DXGI library.");
+ }
- if (SUCCEEDED(result))
+ // create the D3D11 device
+ ASSERT(mDevice == nullptr);
+ D3D11CreateDevice = reinterpret_cast<PFN_D3D11_CREATE_DEVICE>(
+ GetProcAddress(mD3d11Module, "D3D11CreateDevice"));
+
+ if (D3D11CreateDevice == nullptr)
+ {
+ return egl::Error(EGL_NOT_INITIALIZED, D3D11_INIT_MISSING_DEP,
+ "Could not retrieve D3D11CreateDevice address.");
+ }
+ }
+#endif
+
+#ifdef _DEBUG
+ {
+ TRACE_EVENT0("gpu.angle", "D3D11CreateDevice (Debug)");
+ result = D3D11CreateDevice(nullptr, mRequestedDriverType, nullptr,
+ D3D11_CREATE_DEVICE_DEBUG, mAvailableFeatureLevels.data(),
+ static_cast<unsigned int>(mAvailableFeatureLevels.size()),
+ D3D11_SDK_VERSION, &mDevice,
+ &(mRenderer11DeviceCaps.featureLevel), &mDeviceContext);
+ }
+
+ if (!mDevice || FAILED(result))
+ {
+ ERR("Failed creating Debug D3D11 device - falling back to release runtime.\n");
+ }
+
+ if (!mDevice || FAILED(result))
+#endif
+ {
+ SCOPED_ANGLE_HISTOGRAM_TIMER("GPU.ANGLE.D3D11CreateDeviceMS");
+ TRACE_EVENT0("gpu.angle", "D3D11CreateDevice");
+
+ result = D3D11CreateDevice(
+ nullptr, mRequestedDriverType, nullptr, 0, mAvailableFeatureLevels.data(),
+ static_cast<unsigned int>(mAvailableFeatureLevels.size()), D3D11_SDK_VERSION,
+ &mDevice, &(mRenderer11DeviceCaps.featureLevel), &mDeviceContext);
+
+ // Cleanup done by destructor
+ if (!mDevice || FAILED(result))
+ {
+ ANGLE_HISTOGRAM_SPARSE_SLOWLY("GPU.ANGLE.D3D11CreateDeviceError",
+ static_cast<int>(result));
+ return egl::Error(EGL_NOT_INITIALIZED, D3D11_INIT_CREATEDEVICE_ERROR,
+ "Could not create D3D11 device.");
+ }
+ }
+ }
+ else
{
- D3D11_MESSAGE_ID hideMessages[] =
+ // We should use the inputted D3D11 device instead
+ void *device = nullptr;
+ egl::Error error = mEGLDevice->getDevice(&device);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ ID3D11Device *d3dDevice = reinterpret_cast<ID3D11Device *>(device);
+ if (FAILED(d3dDevice->GetDeviceRemovedReason()))
{
- D3D11_MESSAGE_ID_DEVICE_DRAW_RENDERTARGETVIEW_NOT_SET
- };
+ return egl::Error(EGL_NOT_INITIALIZED, "Inputted D3D11 device has been lost.");
+ }
- D3D11_INFO_QUEUE_FILTER filter = {0};
- filter.DenyList.NumIDs = ArraySize(hideMessages);
- filter.DenyList.pIDList = hideMessages;
+ if (d3dDevice->GetFeatureLevel() < D3D_FEATURE_LEVEL_9_3)
+ {
+ return egl::Error(EGL_NOT_INITIALIZED,
+ "Inputted D3D11 device must be Feature Level 9_3 or greater.");
+ }
- infoQueue->AddStorageFilterEntries(&filter);
- SafeRelease(infoQueue);
+ // The Renderer11 adds a ref to the inputted D3D11 device, like D3D11CreateDevice does.
+ mDevice = d3dDevice;
+ mDevice->AddRef();
+ mDevice->GetImmediateContext(&mDeviceContext);
+ mRenderer11DeviceCaps.featureLevel = mDevice->GetFeatureLevel();
}
-#endif
- initializeDevice();
+ d3d11::SetDebugName(mDeviceContext, "DeviceContext");
return egl::Error(EGL_SUCCESS);
}
@@ -568,6 +798,11 @@ egl::Error Renderer11::initialize()
// to reset the scene status and ensure the default states are reset.
void Renderer11::initializeDevice()
{
+ SCOPED_ANGLE_HISTOGRAM_TIMER("GPU.ANGLE.Renderer11InitializeDeviceMS");
+ TRACE_EVENT0("gpu.angle", "Renderer11::initializeDevice");
+
+ populateRenderer11DeviceCaps();
+
mStateCache.initialize(mDevice);
mInputLayoutCache.initialize(mDevice, mDeviceContext);
@@ -598,14 +833,7 @@ void Renderer11::initializeDevice()
const gl::Caps &rendererCaps = getRendererCaps();
-#if defined(ANGLE_ENABLE_D3D11_1)
- if (getDeviceContext1IfSupported())
- {
- D3D11_FEATURE_DATA_D3D11_OPTIONS d3d11Options;
- mDevice->CheckFeatureSupport(D3D11_FEATURE_D3D11_OPTIONS, &d3d11Options, sizeof(D3D11_FEATURE_DATA_D3D11_OPTIONS));
- mSupportsConstantBufferOffsets = (d3d11Options.ConstantBufferOffsetting != FALSE);
- }
-#endif
+ mStateManager.initialize(rendererCaps);
mForceSetVertexSamplerStates.resize(rendererCaps.maxVertexTextureImageUnits);
mCurVertexSamplerStates.resize(rendererCaps.maxVertexTextureImageUnits);
@@ -613,19 +841,94 @@ void Renderer11::initializeDevice()
mForceSetPixelSamplerStates.resize(rendererCaps.maxTextureImageUnits);
mCurPixelSamplerStates.resize(rendererCaps.maxTextureImageUnits);
- mCurVertexSRVs.resize(rendererCaps.maxVertexTextureImageUnits);
- mCurPixelSRVs.resize(rendererCaps.maxTextureImageUnits);
+ mStateManager.initialize(rendererCaps);
markAllStateDirty();
+
+ // Gather stats on DXGI and D3D feature level
+ ANGLE_HISTOGRAM_BOOLEAN("GPU.ANGLE.SupportsDXGI1_2", mRenderer11DeviceCaps.supportsDXGI1_2);
+
+ ANGLEFeatureLevel angleFeatureLevel = GetANGLEFeatureLevel(mRenderer11DeviceCaps.featureLevel);
+
+ // We don't actually request a 11_1 device, because of complications with the platform
+ // update. Instead we check if the mDeviceContext1 pointer cast succeeded.
+ // Note: we should support D3D11_0 always, but we aren't guaranteed to be at FL11_0
+ // because the app can specify a lower version (such as 9_3) on Display creation.
+ if (mDeviceContext1 != nullptr)
+ {
+ angleFeatureLevel = ANGLE_FEATURE_LEVEL_11_1;
+ }
+
+ ANGLE_HISTOGRAM_ENUMERATION("GPU.ANGLE.D3D11FeatureLevel",
+ angleFeatureLevel,
+ NUM_ANGLE_FEATURE_LEVELS);
+
+ // TODO(jmadill): use context caps, and place in common D3D location
+ mTranslatedAttribCache.resize(getRendererCaps().maxVertexAttributes);
+}
+
+void Renderer11::populateRenderer11DeviceCaps()
+{
+ HRESULT hr = S_OK;
+
+#if defined(ANGLE_ENABLE_D3D11_1)
+ if (mDeviceContext1)
+ {
+ D3D11_FEATURE_DATA_D3D11_OPTIONS d3d11Options;
+ HRESULT result = mDevice->CheckFeatureSupport(D3D11_FEATURE_D3D11_OPTIONS, &d3d11Options, sizeof(D3D11_FEATURE_DATA_D3D11_OPTIONS));
+ if (SUCCEEDED(result))
+ {
+ mRenderer11DeviceCaps.supportsClearView = (d3d11Options.ClearView != FALSE);
+ mRenderer11DeviceCaps.supportsConstantBufferOffsets = (d3d11Options.ConstantBufferOffsetting != FALSE);
+ }
+ }
+#endif
+
+ hr = mDevice->CheckFormatSupport(DXGI_FORMAT_B5G6R5_UNORM, &(mRenderer11DeviceCaps.B5G6R5support));
+ if (FAILED(hr))
+ {
+ mRenderer11DeviceCaps.B5G6R5support = 0;
+ }
+
+ hr = mDevice->CheckFormatSupport(DXGI_FORMAT_B4G4R4A4_UNORM, &(mRenderer11DeviceCaps.B4G4R4A4support));
+ if (FAILED(hr))
+ {
+ mRenderer11DeviceCaps.B4G4R4A4support = 0;
+ }
+
+ hr = mDevice->CheckFormatSupport(DXGI_FORMAT_B5G5R5A1_UNORM, &(mRenderer11DeviceCaps.B5G5R5A1support));
+ if (FAILED(hr))
+ {
+ mRenderer11DeviceCaps.B5G5R5A1support = 0;
+ }
+
+#if defined(ANGLE_ENABLE_D3D11_1)
+ IDXGIAdapter2 *dxgiAdapter2 = d3d11::DynamicCastComObject<IDXGIAdapter2>(mDxgiAdapter);
+ mRenderer11DeviceCaps.supportsDXGI1_2 = (dxgiAdapter2 != nullptr);
+ SafeRelease(dxgiAdapter2);
+#endif
}
egl::ConfigSet Renderer11::generateConfigs() const
{
- static const GLenum colorBufferFormats[] =
+ std::vector<GLenum> colorBufferFormats;
+
+ // 32-bit supported formats
+ colorBufferFormats.push_back(GL_BGRA8_EXT);
+ colorBufferFormats.push_back(GL_RGBA8_OES);
+
+ // 24-bit supported formats
+ colorBufferFormats.push_back(GL_RGB8_OES);
+
+ if (!mPresentPathFastEnabled)
{
- GL_BGRA8_EXT,
- GL_RGBA8_OES,
- };
+ // 16-bit supported formats
+ // These aren't valid D3D11 swapchain formats, so don't expose them as configs
+ // if present path fast is active
+ colorBufferFormats.push_back(GL_RGBA4);
+ colorBufferFormats.push_back(GL_RGB5_A1);
+ colorBufferFormats.push_back(GL_RGB565);
+ }
static const GLenum depthStencilBufferFormats[] =
{
@@ -637,64 +940,87 @@ egl::ConfigSet Renderer11::generateConfigs() const
const gl::Caps &rendererCaps = getRendererCaps();
const gl::TextureCapsMap &rendererTextureCaps = getRendererTextureCaps();
+ const EGLint optimalSurfaceOrientation =
+ mPresentPathFastEnabled ? 0 : EGL_SURFACE_ORIENTATION_INVERT_Y_ANGLE;
+
egl::ConfigSet configs;
- for (size_t formatIndex = 0; formatIndex < ArraySize(colorBufferFormats); formatIndex++)
+ for (GLenum colorBufferInternalFormat : colorBufferFormats)
{
- GLenum colorBufferInternalFormat = colorBufferFormats[formatIndex];
const gl::TextureCaps &colorBufferFormatCaps = rendererTextureCaps.get(colorBufferInternalFormat);
- if (colorBufferFormatCaps.renderable)
+ if (!colorBufferFormatCaps.renderable)
{
- for (size_t depthStencilIndex = 0; depthStencilIndex < ArraySize(depthStencilBufferFormats); depthStencilIndex++)
+ continue;
+ }
+
+ for (GLenum depthStencilBufferInternalFormat : depthStencilBufferFormats)
+ {
+ const gl::TextureCaps &depthStencilBufferFormatCaps =
+ rendererTextureCaps.get(depthStencilBufferInternalFormat);
+ if (!depthStencilBufferFormatCaps.renderable &&
+ depthStencilBufferInternalFormat != GL_NONE)
{
- GLenum depthStencilBufferInternalFormat = depthStencilBufferFormats[depthStencilIndex];
- const gl::TextureCaps &depthStencilBufferFormatCaps = rendererTextureCaps.get(depthStencilBufferInternalFormat);
- if (depthStencilBufferFormatCaps.renderable || depthStencilBufferInternalFormat == GL_NONE)
- {
- const gl::InternalFormat &colorBufferFormatInfo = gl::GetInternalFormatInfo(colorBufferInternalFormat);
- const gl::InternalFormat &depthStencilBufferFormatInfo = gl::GetInternalFormatInfo(depthStencilBufferInternalFormat);
-
- egl::Config config;
- config.renderTargetFormat = colorBufferInternalFormat;
- config.depthStencilFormat = depthStencilBufferInternalFormat;
- config.bufferSize = colorBufferFormatInfo.pixelBytes * 8;
- config.redSize = colorBufferFormatInfo.redBits;
- config.greenSize = colorBufferFormatInfo.greenBits;
- config.blueSize = colorBufferFormatInfo.blueBits;
- config.luminanceSize = colorBufferFormatInfo.luminanceBits;
- config.alphaSize = colorBufferFormatInfo.alphaBits;
- config.alphaMaskSize = 0;
- config.bindToTextureRGB = (colorBufferFormatInfo.format == GL_RGB);
- config.bindToTextureRGBA = (colorBufferFormatInfo.format == GL_RGBA || colorBufferFormatInfo.format == GL_BGRA_EXT);
- config.colorBufferType = EGL_RGB_BUFFER;
- config.configID = static_cast<EGLint>(configs.size() + 1);
- // Can only support a conformant ES2 with feature level greater than 10.0.
- config.conformant = (mFeatureLevel >= D3D_FEATURE_LEVEL_10_0) ? (EGL_OPENGL_ES2_BIT | EGL_OPENGL_ES3_BIT_KHR) : EGL_NONE;
- config.configCaveat = config.conformant == EGL_NONE ? EGL_NON_CONFORMANT_CONFIG : EGL_NONE;
- config.depthSize = depthStencilBufferFormatInfo.depthBits;
- config.level = 0;
- config.matchNativePixmap = EGL_NONE;
- config.maxPBufferWidth = rendererCaps.max2DTextureSize;
- config.maxPBufferHeight = rendererCaps.max2DTextureSize;
- config.maxPBufferPixels = rendererCaps.max2DTextureSize * rendererCaps.max2DTextureSize;
- config.maxSwapInterval = 4;
- config.minSwapInterval = 0;
- config.nativeRenderable = EGL_FALSE;
- config.nativeVisualID = 0;
- config.nativeVisualType = EGL_NONE;
- // Can't support ES3 at all without feature level 10.0
- config.renderableType = EGL_OPENGL_ES2_BIT | ((mFeatureLevel >= D3D_FEATURE_LEVEL_10_0) ? EGL_OPENGL_ES3_BIT_KHR : 0);
- config.sampleBuffers = 0; // FIXME: enumerate multi-sampling
- config.samples = 0;
- config.stencilSize = depthStencilBufferFormatInfo.stencilBits;
- config.surfaceType = EGL_PBUFFER_BIT | EGL_WINDOW_BIT | EGL_SWAP_BEHAVIOR_PRESERVED_BIT;
- config.transparentType = EGL_NONE;
- config.transparentRedValue = 0;
- config.transparentGreenValue = 0;
- config.transparentBlueValue = 0;
-
- configs.add(config);
- }
+ continue;
+ }
+
+ const gl::InternalFormat &colorBufferFormatInfo =
+ gl::GetInternalFormatInfo(colorBufferInternalFormat);
+ const gl::InternalFormat &depthStencilBufferFormatInfo =
+ gl::GetInternalFormatInfo(depthStencilBufferInternalFormat);
+
+ egl::Config config;
+ config.renderTargetFormat = colorBufferInternalFormat;
+ config.depthStencilFormat = depthStencilBufferInternalFormat;
+ config.bufferSize = colorBufferFormatInfo.pixelBytes * 8;
+ config.redSize = colorBufferFormatInfo.redBits;
+ config.greenSize = colorBufferFormatInfo.greenBits;
+ config.blueSize = colorBufferFormatInfo.blueBits;
+ config.luminanceSize = colorBufferFormatInfo.luminanceBits;
+ config.alphaSize = colorBufferFormatInfo.alphaBits;
+ config.alphaMaskSize = 0;
+ config.bindToTextureRGB = (colorBufferFormatInfo.format == GL_RGB);
+ config.bindToTextureRGBA = (colorBufferFormatInfo.format == GL_RGBA ||
+ colorBufferFormatInfo.format == GL_BGRA_EXT);
+ config.colorBufferType = EGL_RGB_BUFFER;
+ config.configID = static_cast<EGLint>(configs.size() + 1);
+ // Can only support a conformant ES2 with feature level greater than 10.0.
+ config.conformant = (mRenderer11DeviceCaps.featureLevel >= D3D_FEATURE_LEVEL_10_0)
+ ? (EGL_OPENGL_ES2_BIT | EGL_OPENGL_ES3_BIT_KHR)
+ : 0;
+ config.configCaveat = config.conformant == EGL_NONE ? EGL_NON_CONFORMANT_CONFIG : EGL_NONE;
+
+ // PresentPathFast may not be conformant
+ if (mPresentPathFastEnabled)
+ {
+ config.conformant = 0;
}
+
+ config.depthSize = depthStencilBufferFormatInfo.depthBits;
+ config.level = 0;
+ config.matchNativePixmap = EGL_NONE;
+ config.maxPBufferWidth = rendererCaps.max2DTextureSize;
+ config.maxPBufferHeight = rendererCaps.max2DTextureSize;
+ config.maxPBufferPixels = rendererCaps.max2DTextureSize * rendererCaps.max2DTextureSize;
+ config.maxSwapInterval = 4;
+ config.minSwapInterval = 0;
+ config.nativeRenderable = EGL_FALSE;
+ config.nativeVisualID = 0;
+ config.nativeVisualType = EGL_NONE;
+ // Can't support ES3 at all without feature level 10.0
+ config.renderableType =
+ EGL_OPENGL_ES2_BIT | ((mRenderer11DeviceCaps.featureLevel >= D3D_FEATURE_LEVEL_10_0)
+ ? EGL_OPENGL_ES3_BIT_KHR
+ : 0);
+ config.sampleBuffers = 0; // FIXME: enumerate multi-sampling
+ config.samples = 0;
+ config.stencilSize = depthStencilBufferFormatInfo.stencilBits;
+ config.surfaceType = EGL_PBUFFER_BIT | EGL_WINDOW_BIT | EGL_SWAP_BEHAVIOR_PRESERVED_BIT;
+ config.transparentType = EGL_NONE;
+ config.transparentRedValue = 0;
+ config.transparentGreenValue = 0;
+ config.transparentBlueValue = 0;
+ config.optimalOrientation = optimalSurfaceOrientation;
+
+ configs.add(config);
}
}
@@ -702,6 +1028,42 @@ egl::ConfigSet Renderer11::generateConfigs() const
return configs;
}
+void Renderer11::generateDisplayExtensions(egl::DisplayExtensions *outExtensions) const
+{
+ outExtensions->createContextRobustness = true;
+
+ if (getShareHandleSupport())
+ {
+ outExtensions->d3dShareHandleClientBuffer = true;
+ outExtensions->surfaceD3DTexture2DShareHandle = true;
+ }
+
+ outExtensions->keyedMutex = true;
+ outExtensions->querySurfacePointer = true;
+ outExtensions->windowFixedSize = true;
+
+ // If present path fast is active then the surface orientation extension isn't supported
+ outExtensions->surfaceOrientation = !mPresentPathFastEnabled;
+
+ // D3D11 does not support present with dirty rectangles until DXGI 1.2.
+ outExtensions->postSubBuffer = mRenderer11DeviceCaps.supportsDXGI1_2;
+
+ outExtensions->createContext = true;
+
+ outExtensions->deviceQuery = true;
+
+ outExtensions->createContextNoError = true;
+
+ outExtensions->image = true;
+ outExtensions->imageBase = true;
+ outExtensions->glTexture2DImage = true;
+ outExtensions->glTextureCubemapImage = true;
+ outExtensions->glRenderbufferImage = true;
+
+ outExtensions->flexibleSurfaceCompatibility = true;
+ outExtensions->directComposition = !!mDCompModule;
+}
+
gl::Error Renderer11::flush()
{
mDeviceContext->Flush();
@@ -751,9 +1113,31 @@ gl::Error Renderer11::finish()
return gl::Error(GL_NO_ERROR);
}
-SwapChainD3D *Renderer11::createSwapChain(NativeWindow nativeWindow, HANDLE shareHandle, GLenum backBufferFormat, GLenum depthBufferFormat)
+SwapChainD3D *Renderer11::createSwapChain(NativeWindow nativeWindow,
+ HANDLE shareHandle,
+ GLenum backBufferFormat,
+ GLenum depthBufferFormat,
+ EGLint orientation)
+{
+ return new SwapChain11(this, nativeWindow, shareHandle, backBufferFormat, depthBufferFormat,
+ orientation);
+}
+
+CompilerImpl *Renderer11::createCompiler()
+{
+ if (mRenderer11DeviceCaps.featureLevel <= D3D_FEATURE_LEVEL_9_3)
+ {
+ return new CompilerD3D(SH_HLSL_4_0_FL9_3_OUTPUT);
+ }
+ else
+ {
+ return new CompilerD3D(SH_HLSL_4_1_OUTPUT);
+ }
+}
+
+void *Renderer11::getD3DDevice()
{
- return new SwapChain11(this, nativeWindow, shareHandle, backBufferFormat, depthBufferFormat);
+ return reinterpret_cast<void*>(mDevice);
}
gl::Error Renderer11::generateSwizzle(gl::Texture *texture)
@@ -772,11 +1156,11 @@ gl::Error Renderer11::generateSwizzle(gl::Texture *texture)
if (texStorage)
{
- TextureStorage11 *storage11 = TextureStorage11::makeTextureStorage11(texStorage);
- error = storage11->generateSwizzles(texture->getSamplerState().swizzleRed,
- texture->getSamplerState().swizzleGreen,
- texture->getSamplerState().swizzleBlue,
- texture->getSamplerState().swizzleAlpha);
+ TextureStorage11 *storage11 = GetAs<TextureStorage11>(texStorage);
+ const gl::TextureState &textureState = texture->getTextureState();
+ error =
+ storage11->generateSwizzles(textureState.swizzleRed, textureState.swizzleGreen,
+ textureState.swizzleBlue, textureState.swizzleAlpha);
if (error.isError())
{
return error;
@@ -787,11 +1171,13 @@ gl::Error Renderer11::generateSwizzle(gl::Texture *texture)
return gl::Error(GL_NO_ERROR);
}
-gl::Error Renderer11::setSamplerState(gl::SamplerType type, int index, gl::Texture *texture, const gl::SamplerState &samplerStateParam)
+gl::Error Renderer11::setSamplerState(gl::SamplerType type,
+ int index,
+ gl::Texture *texture,
+ const gl::SamplerState &samplerState)
{
// Make sure to add the level offset for our tiny compressed texture workaround
TextureD3D *textureD3D = GetImplAs<TextureD3D>(texture);
- gl::SamplerState samplerStateInternal = samplerStateParam;
TextureStorage *storage = nullptr;
gl::Error error = textureD3D->getNativeTexture(&storage);
@@ -803,16 +1189,15 @@ gl::Error Renderer11::setSamplerState(gl::SamplerType type, int index, gl::Textu
// Storage should exist, texture should be complete
ASSERT(storage);
- samplerStateInternal.baseLevel += storage->getTopLevel();
-
if (type == gl::SAMPLER_PIXEL)
{
ASSERT(static_cast<unsigned int>(index) < getRendererCaps().maxTextureImageUnits);
- if (mForceSetPixelSamplerStates[index] || memcmp(&samplerStateInternal, &mCurPixelSamplerStates[index], sizeof(gl::SamplerState)) != 0)
+ if (mForceSetPixelSamplerStates[index] ||
+ memcmp(&samplerState, &mCurPixelSamplerStates[index], sizeof(gl::SamplerState)) != 0)
{
ID3D11SamplerState *dxSamplerState = NULL;
- error = mStateCache.getSamplerState(samplerStateInternal, &dxSamplerState);
+ error = mStateCache.getSamplerState(samplerState, &dxSamplerState);
if (error.isError())
{
return error;
@@ -821,7 +1206,7 @@ gl::Error Renderer11::setSamplerState(gl::SamplerType type, int index, gl::Textu
ASSERT(dxSamplerState != NULL);
mDeviceContext->PSSetSamplers(index, 1, &dxSamplerState);
- mCurPixelSamplerStates[index] = samplerStateInternal;
+ mCurPixelSamplerStates[index] = samplerState;
}
mForceSetPixelSamplerStates[index] = false;
@@ -830,10 +1215,11 @@ gl::Error Renderer11::setSamplerState(gl::SamplerType type, int index, gl::Textu
{
ASSERT(static_cast<unsigned int>(index) < getRendererCaps().maxVertexTextureImageUnits);
- if (mForceSetVertexSamplerStates[index] || memcmp(&samplerStateInternal, &mCurVertexSamplerStates[index], sizeof(gl::SamplerState)) != 0)
+ if (mForceSetVertexSamplerStates[index] ||
+ memcmp(&samplerState, &mCurVertexSamplerStates[index], sizeof(gl::SamplerState)) != 0)
{
ID3D11SamplerState *dxSamplerState = NULL;
- error = mStateCache.getSamplerState(samplerStateInternal, &dxSamplerState);
+ error = mStateCache.getSamplerState(samplerState, &dxSamplerState);
if (error.isError())
{
return error;
@@ -842,7 +1228,7 @@ gl::Error Renderer11::setSamplerState(gl::SamplerType type, int index, gl::Textu
ASSERT(dxSamplerState != NULL);
mDeviceContext->VSSetSamplers(index, 1, &dxSamplerState);
- mCurVertexSamplerStates[index] = samplerStateInternal;
+ mCurVertexSamplerStates[index] = samplerState;
}
mForceSetVertexSamplerStates[index] = false;
@@ -870,13 +1256,13 @@ gl::Error Renderer11::setTexture(gl::SamplerType type, int index, gl::Texture *t
// Texture should be complete and have a storage
ASSERT(texStorage);
- TextureStorage11 *storage11 = TextureStorage11::makeTextureStorage11(texStorage);
+ TextureStorage11 *storage11 = GetAs<TextureStorage11>(texStorage);
// Make sure to add the level offset for our tiny compressed texture workaround
- gl::SamplerState samplerState = texture->getSamplerState();
- samplerState.baseLevel += storage11->getTopLevel();
+ gl::TextureState textureState = texture->getTextureState();
+ textureState.baseLevel += storage11->getTopLevel();
- error = storage11->getSRV(samplerState, &textureSRV);
+ error = storage11->getSRV(textureState, &textureSRV);
if (error.isError())
{
return error;
@@ -892,16 +1278,16 @@ gl::Error Renderer11::setTexture(gl::SamplerType type, int index, gl::Texture *t
ASSERT((type == gl::SAMPLER_PIXEL && static_cast<unsigned int>(index) < getRendererCaps().maxTextureImageUnits) ||
(type == gl::SAMPLER_VERTEX && static_cast<unsigned int>(index) < getRendererCaps().maxVertexTextureImageUnits));
- setShaderResource(type, index, textureSRV);
+ mStateManager.setShaderResource(type, index, textureSRV);
return gl::Error(GL_NO_ERROR);
}
gl::Error Renderer11::setUniformBuffers(const gl::Data &data,
- const GLint vertexUniformBuffers[],
- const GLint fragmentUniformBuffers[])
+ const std::vector<GLint> &vertexUniformBuffers,
+ const std::vector<GLint> &fragmentUniformBuffers)
{
- for (unsigned int uniformBufferIndex = 0; uniformBufferIndex < data.caps->maxVertexUniformBlocks; uniformBufferIndex++)
+ for (size_t uniformBufferIndex = 0; uniformBufferIndex < vertexUniformBuffers.size(); uniformBufferIndex++)
{
GLint binding = vertexUniformBuffers[uniformBufferIndex];
@@ -910,14 +1296,24 @@ gl::Error Renderer11::setUniformBuffers(const gl::Data &data,
continue;
}
- gl::Buffer *uniformBuffer = data.state->getIndexedUniformBuffer(binding);
- GLintptr uniformBufferOffset = data.state->getIndexedUniformBufferOffset(binding);
- GLsizeiptr uniformBufferSize = data.state->getIndexedUniformBufferSize(binding);
+ const OffsetBindingPointer<gl::Buffer> &uniformBuffer =
+ data.state->getIndexedUniformBuffer(binding);
+ GLintptr uniformBufferOffset = uniformBuffer.getOffset();
+ GLsizeiptr uniformBufferSize = uniformBuffer.getSize();
- if (uniformBuffer)
+ if (uniformBuffer.get() != nullptr)
{
- Buffer11 *bufferStorage = Buffer11::makeBuffer11(uniformBuffer->getImplementation());
- ID3D11Buffer *constantBuffer = bufferStorage->getBuffer(BUFFER_USAGE_UNIFORM);
+ Buffer11 *bufferStorage = GetImplAs<Buffer11>(uniformBuffer.get());
+ ID3D11Buffer *constantBuffer;
+
+ if (mRenderer11DeviceCaps.supportsConstantBufferOffsets)
+ {
+ constantBuffer = bufferStorage->getBuffer(BUFFER_USAGE_UNIFORM);
+ }
+ else
+ {
+ constantBuffer = bufferStorage->getConstantBufferRange(uniformBufferOffset, uniformBufferSize);
+ }
if (!constantBuffer)
{
@@ -929,19 +1325,22 @@ gl::Error Renderer11::setUniformBuffers(const gl::Data &data,
mCurrentConstantBufferVSSize[uniformBufferIndex] != uniformBufferSize)
{
#if defined(ANGLE_ENABLE_D3D11_1)
- if (mSupportsConstantBufferOffsets && uniformBufferSize != 0)
+ if (mRenderer11DeviceCaps.supportsConstantBufferOffsets && uniformBufferSize != 0)
{
UINT firstConstant = 0, numConstants = 0;
CalculateConstantBufferParams(uniformBufferOffset, uniformBufferSize, &firstConstant, &numConstants);
- mDeviceContext1->VSSetConstantBuffers1(getReservedVertexUniformBuffers() + uniformBufferIndex,
- 1, &constantBuffer, &firstConstant, &numConstants);
+ mDeviceContext1->VSSetConstantBuffers1(
+ getReservedVertexUniformBuffers() +
+ static_cast<unsigned int>(uniformBufferIndex),
+ 1, &constantBuffer, &firstConstant, &numConstants);
}
else
#endif
{
- ASSERT(uniformBufferOffset == 0);
- mDeviceContext->VSSetConstantBuffers(getReservedVertexUniformBuffers() + uniformBufferIndex,
- 1, &constantBuffer);
+ mDeviceContext->VSSetConstantBuffers(
+ getReservedVertexUniformBuffers() +
+ static_cast<unsigned int>(uniformBufferIndex),
+ 1, &constantBuffer);
}
mCurrentConstantBufferVS[uniformBufferIndex] = bufferStorage->getSerial();
@@ -951,7 +1350,7 @@ gl::Error Renderer11::setUniformBuffers(const gl::Data &data,
}
}
- for (unsigned int uniformBufferIndex = 0; uniformBufferIndex < data.caps->maxFragmentUniformBlocks; uniformBufferIndex++)
+ for (size_t uniformBufferIndex = 0; uniformBufferIndex < fragmentUniformBuffers.size(); uniformBufferIndex++)
{
GLint binding = fragmentUniformBuffers[uniformBufferIndex];
@@ -960,14 +1359,24 @@ gl::Error Renderer11::setUniformBuffers(const gl::Data &data,
continue;
}
- gl::Buffer *uniformBuffer = data.state->getIndexedUniformBuffer(binding);
- GLintptr uniformBufferOffset = data.state->getIndexedUniformBufferOffset(binding);
- GLsizeiptr uniformBufferSize = data.state->getIndexedUniformBufferSize(binding);
+ const OffsetBindingPointer<gl::Buffer> &uniformBuffer =
+ data.state->getIndexedUniformBuffer(binding);
+ GLintptr uniformBufferOffset = uniformBuffer.getOffset();
+ GLsizeiptr uniformBufferSize = uniformBuffer.getSize();
- if (uniformBuffer)
+ if (uniformBuffer.get() != nullptr)
{
- Buffer11 *bufferStorage = Buffer11::makeBuffer11(uniformBuffer->getImplementation());
- ID3D11Buffer *constantBuffer = bufferStorage->getBuffer(BUFFER_USAGE_UNIFORM);
+ Buffer11 *bufferStorage = GetImplAs<Buffer11>(uniformBuffer.get());
+ ID3D11Buffer *constantBuffer;
+
+ if (mRenderer11DeviceCaps.supportsConstantBufferOffsets)
+ {
+ constantBuffer = bufferStorage->getBuffer(BUFFER_USAGE_UNIFORM);
+ }
+ else
+ {
+ constantBuffer = bufferStorage->getConstantBufferRange(uniformBufferOffset, uniformBufferSize);
+ }
if (!constantBuffer)
{
@@ -979,19 +1388,22 @@ gl::Error Renderer11::setUniformBuffers(const gl::Data &data,
mCurrentConstantBufferPSSize[uniformBufferIndex] != uniformBufferSize)
{
#if defined(ANGLE_ENABLE_D3D11_1)
- if (mSupportsConstantBufferOffsets && uniformBufferSize != 0)
+ if (mRenderer11DeviceCaps.supportsConstantBufferOffsets && uniformBufferSize != 0)
{
UINT firstConstant = 0, numConstants = 0;
CalculateConstantBufferParams(uniformBufferOffset, uniformBufferSize, &firstConstant, &numConstants);
- mDeviceContext1->PSSetConstantBuffers1(getReservedFragmentUniformBuffers() + uniformBufferIndex,
- 1, &constantBuffer, &firstConstant, &numConstants);
+ mDeviceContext1->PSSetConstantBuffers1(
+ getReservedFragmentUniformBuffers() +
+ static_cast<unsigned int>(uniformBufferIndex),
+ 1, &constantBuffer, &firstConstant, &numConstants);
}
else
#endif
{
- ASSERT(uniformBufferOffset == 0);
- mDeviceContext->PSSetConstantBuffers(getReservedFragmentUniformBuffers() + uniformBufferIndex,
- 1, &constantBuffer);
+ mDeviceContext->PSSetConstantBuffers(
+ getReservedFragmentUniformBuffers() +
+ static_cast<unsigned int>(uniformBufferIndex),
+ 1, &constantBuffer);
}
mCurrentConstantBufferPS[uniformBufferIndex] = bufferStorage->getSerial();
@@ -1004,229 +1416,60 @@ gl::Error Renderer11::setUniformBuffers(const gl::Data &data,
return gl::Error(GL_NO_ERROR);
}
-gl::Error Renderer11::setRasterizerState(const gl::RasterizerState &rasterState)
+gl::Error Renderer11::updateState(const gl::Data &data, GLenum drawMode)
{
- if (mForceSetRasterState || memcmp(&rasterState, &mCurRasterState, sizeof(gl::RasterizerState)) != 0)
+ // Applies the render target surface, depth stencil surface, viewport rectangle and
+ // scissor rectangle to the renderer
+ const gl::Framebuffer *framebufferObject = data.state->getDrawFramebuffer();
+ ASSERT(framebufferObject && framebufferObject->checkStatus(data) == GL_FRAMEBUFFER_COMPLETE);
+ gl::Error error = applyRenderTarget(framebufferObject);
+ if (error.isError())
{
- ID3D11RasterizerState *dxRasterState = NULL;
- gl::Error error = mStateCache.getRasterizerState(rasterState, mScissorEnabled, &dxRasterState);
- if (error.isError())
- {
- return error;
- }
-
- mDeviceContext->RSSetState(dxRasterState);
-
- mCurRasterState = rasterState;
+ return error;
}
- mForceSetRasterState = false;
+ // Set the present path state
+ const bool presentPathFastActive =
+ UsePresentPathFast(this, framebufferObject->getFirstColorbuffer());
+ mStateManager.updatePresentPath(presentPathFastActive,
+ framebufferObject->getFirstColorbuffer());
- return gl::Error(GL_NO_ERROR);
-}
+ // Setting viewport state
+ mStateManager.setViewport(data.caps, data.state->getViewport(), data.state->getNearPlane(),
+ data.state->getFarPlane());
-gl::Error Renderer11::setBlendState(const gl::Framebuffer *framebuffer, const gl::BlendState &blendState, const gl::ColorF &blendColor,
- unsigned int sampleMask)
-{
- if (mForceSetBlendState ||
- memcmp(&blendState, &mCurBlendState, sizeof(gl::BlendState)) != 0 ||
- memcmp(&blendColor, &mCurBlendColor, sizeof(gl::ColorF)) != 0 ||
- sampleMask != mCurSampleMask)
- {
- ID3D11BlendState *dxBlendState = NULL;
- gl::Error error = mStateCache.getBlendState(framebuffer, blendState, &dxBlendState);
- if (error.isError())
- {
- return error;
- }
-
- ASSERT(dxBlendState != NULL);
-
- float blendColors[4] = {0.0f};
- if (blendState.sourceBlendRGB != GL_CONSTANT_ALPHA && blendState.sourceBlendRGB != GL_ONE_MINUS_CONSTANT_ALPHA &&
- blendState.destBlendRGB != GL_CONSTANT_ALPHA && blendState.destBlendRGB != GL_ONE_MINUS_CONSTANT_ALPHA)
- {
- blendColors[0] = blendColor.red;
- blendColors[1] = blendColor.green;
- blendColors[2] = blendColor.blue;
- blendColors[3] = blendColor.alpha;
- }
- else
- {
- blendColors[0] = blendColor.alpha;
- blendColors[1] = blendColor.alpha;
- blendColors[2] = blendColor.alpha;
- blendColors[3] = blendColor.alpha;
- }
-
- mDeviceContext->OMSetBlendState(dxBlendState, blendColors, sampleMask);
-
- mCurBlendState = blendState;
- mCurBlendColor = blendColor;
- mCurSampleMask = sampleMask;
- }
+ // Setting scissor state
+ mStateManager.setScissorRectangle(data.state->getScissor(), data.state->isScissorTestEnabled());
- mForceSetBlendState = false;
+ // Applying rasterizer state to D3D11 device
+ int samples = framebufferObject->getSamples(data);
+ gl::RasterizerState rasterizer = data.state->getRasterizerState();
+ rasterizer.pointDrawMode = (drawMode == GL_POINTS);
+ rasterizer.multiSample = (samples != 0);
- return gl::Error(GL_NO_ERROR);
-}
-
-gl::Error Renderer11::setDepthStencilState(const gl::DepthStencilState &depthStencilState, int stencilRef,
- int stencilBackRef, bool frontFaceCCW)
-{
- if (mForceSetDepthStencilState ||
- memcmp(&depthStencilState, &mCurDepthStencilState, sizeof(gl::DepthStencilState)) != 0 ||
- stencilRef != mCurStencilRef || stencilBackRef != mCurStencilBackRef)
+ error = mStateManager.setRasterizerState(rasterizer);
+ if (error.isError())
{
- ASSERT(depthStencilState.stencilWritemask == depthStencilState.stencilBackWritemask);
- ASSERT(stencilRef == stencilBackRef);
- ASSERT(depthStencilState.stencilMask == depthStencilState.stencilBackMask);
-
- ID3D11DepthStencilState *dxDepthStencilState = NULL;
- gl::Error error = mStateCache.getDepthStencilState(depthStencilState, &dxDepthStencilState);
- if (error.isError())
- {
- return error;
- }
-
- ASSERT(dxDepthStencilState);
-
- // Max D3D11 stencil reference value is 0xFF, corresponding to the max 8 bits in a stencil buffer
- // GL specifies we should clamp the ref value to the nearest bit depth when doing stencil ops
- static_assert(D3D11_DEFAULT_STENCIL_READ_MASK == 0xFF, "Unexpected value of D3D11_DEFAULT_STENCIL_READ_MASK");
- static_assert(D3D11_DEFAULT_STENCIL_WRITE_MASK == 0xFF, "Unexpected value of D3D11_DEFAULT_STENCIL_WRITE_MASK");
- UINT dxStencilRef = std::min<UINT>(stencilRef, 0xFFu);
-
- mDeviceContext->OMSetDepthStencilState(dxDepthStencilState, dxStencilRef);
-
- mCurDepthStencilState = depthStencilState;
- mCurStencilRef = stencilRef;
- mCurStencilBackRef = stencilBackRef;
+ return error;
}
- mForceSetDepthStencilState = false;
-
- return gl::Error(GL_NO_ERROR);
-}
-
-void Renderer11::setScissorRectangle(const gl::Rectangle &scissor, bool enabled)
-{
- if (mForceSetScissor || memcmp(&scissor, &mCurScissor, sizeof(gl::Rectangle)) != 0 ||
- enabled != mScissorEnabled)
+ // Setting blend state
+ unsigned int mask = GetBlendSampleMask(data, samples);
+ error = mStateManager.setBlendState(framebufferObject, data.state->getBlendState(),
+ data.state->getBlendColor(), mask);
+ if (error.isError())
{
- if (enabled)
- {
- D3D11_RECT rect;
- rect.left = std::max(0, scissor.x);
- rect.top = std::max(0, scissor.y);
- rect.right = scissor.x + std::max(0, scissor.width);
- rect.bottom = scissor.y + std::max(0, scissor.height);
-
- mDeviceContext->RSSetScissorRects(1, &rect);
- }
-
- if (enabled != mScissorEnabled)
- {
- mForceSetRasterState = true;
- }
-
- mCurScissor = scissor;
- mScissorEnabled = enabled;
+ return error;
}
- mForceSetScissor = false;
+ // Setting depth stencil state
+ error = mStateManager.setDepthStencilState(*data.state);
+ return error;
}
-void Renderer11::setViewport(const gl::Rectangle &viewport, float zNear, float zFar, GLenum drawMode, GLenum frontFace,
- bool ignoreViewport)
+void Renderer11::syncState(const gl::State &state, const gl::State::DirtyBits &bitmask)
{
- gl::Rectangle actualViewport = viewport;
- float actualZNear = gl::clamp01(zNear);
- float actualZFar = gl::clamp01(zFar);
- if (ignoreViewport)
- {
- actualViewport.x = 0;
- actualViewport.y = 0;
- actualViewport.width = mRenderTargetDesc.width;
- actualViewport.height = mRenderTargetDesc.height;
- actualZNear = 0.0f;
- actualZFar = 1.0f;
- }
-
- bool viewportChanged = mForceSetViewport || memcmp(&actualViewport, &mCurViewport, sizeof(gl::Rectangle)) != 0 ||
- actualZNear != mCurNear || actualZFar != mCurFar;
-
- if (viewportChanged)
- {
- const gl::Caps& caps = getRendererCaps();
-
- int dxMaxViewportBoundsX = static_cast<int>(caps.maxViewportWidth);
- int dxMaxViewportBoundsY = static_cast<int>(caps.maxViewportHeight);
- int dxMinViewportBoundsX = -dxMaxViewportBoundsX;
- int dxMinViewportBoundsY = -dxMaxViewportBoundsY;
-
- if (mFeatureLevel <= D3D_FEATURE_LEVEL_9_3)
- {
- // Feature Level 9 viewports shouldn't exceed the dimensions of the rendertarget.
- dxMaxViewportBoundsX = mRenderTargetDesc.width;
- dxMaxViewportBoundsY = mRenderTargetDesc.height;
- dxMinViewportBoundsX = 0;
- dxMinViewportBoundsY = 0;
- }
-
- int dxViewportTopLeftX = gl::clamp(actualViewport.x, dxMinViewportBoundsX, dxMaxViewportBoundsX);
- int dxViewportTopLeftY = gl::clamp(actualViewport.y, dxMinViewportBoundsY, dxMaxViewportBoundsY);
- int dxViewportWidth = gl::clamp(actualViewport.width, 0, dxMaxViewportBoundsX - dxViewportTopLeftX);
- int dxViewportHeight = gl::clamp(actualViewport.height, 0, dxMaxViewportBoundsY - dxViewportTopLeftY);
-
- D3D11_VIEWPORT dxViewport;
- dxViewport.TopLeftX = static_cast<float>(dxViewportTopLeftX);
- dxViewport.TopLeftY = static_cast<float>(dxViewportTopLeftY);
- dxViewport.Width = static_cast<float>(dxViewportWidth);
- dxViewport.Height = static_cast<float>(dxViewportHeight);
- dxViewport.MinDepth = actualZNear;
- dxViewport.MaxDepth = actualZFar;
-
- mDeviceContext->RSSetViewports(1, &dxViewport);
-
- mCurViewport = actualViewport;
- mCurNear = actualZNear;
- mCurFar = actualZFar;
-
- // On Feature Level 9_*, we must emulate large and/or negative viewports in the shaders using viewAdjust (like the D3D9 renderer).
- if (mFeatureLevel <= D3D_FEATURE_LEVEL_9_3)
- {
- mVertexConstants.viewAdjust[0] = static_cast<float>((actualViewport.width - dxViewportWidth) + 2 * (actualViewport.x - dxViewportTopLeftX)) / dxViewport.Width;
- mVertexConstants.viewAdjust[1] = static_cast<float>((actualViewport.height - dxViewportHeight) + 2 * (actualViewport.y - dxViewportTopLeftY)) / dxViewport.Height;
- mVertexConstants.viewAdjust[2] = static_cast<float>(actualViewport.width) / dxViewport.Width;
- mVertexConstants.viewAdjust[3] = static_cast<float>(actualViewport.height) / dxViewport.Height;
- }
-
- mPixelConstants.viewCoords[0] = actualViewport.width * 0.5f;
- mPixelConstants.viewCoords[1] = actualViewport.height * 0.5f;
- mPixelConstants.viewCoords[2] = actualViewport.x + (actualViewport.width * 0.5f);
- mPixelConstants.viewCoords[3] = actualViewport.y + (actualViewport.height * 0.5f);
-
- // Instanced pointsprite emulation requires ViewCoords to be defined in the
- // the vertex shader.
- mVertexConstants.viewCoords[0] = mPixelConstants.viewCoords[0];
- mVertexConstants.viewCoords[1] = mPixelConstants.viewCoords[1];
- mVertexConstants.viewCoords[2] = mPixelConstants.viewCoords[2];
- mVertexConstants.viewCoords[3] = mPixelConstants.viewCoords[3];
-
- mPixelConstants.depthFront[0] = (actualZFar - actualZNear) * 0.5f;
- mPixelConstants.depthFront[1] = (actualZNear + actualZFar) * 0.5f;
-
- mVertexConstants.depthRange[0] = actualZNear;
- mVertexConstants.depthRange[1] = actualZFar;
- mVertexConstants.depthRange[2] = actualZFar - actualZNear;
-
- mPixelConstants.depthRange[0] = actualZNear;
- mPixelConstants.depthRange[1] = actualZFar;
- mPixelConstants.depthRange[2] = actualZFar - actualZNear;
- }
-
- mForceSetViewport = false;
+ mStateManager.syncState(state, bitmask);
}
bool Renderer11::applyPrimitiveType(GLenum mode, GLsizei count, bool usesPointSize)
@@ -1267,176 +1510,51 @@ bool Renderer11::applyPrimitiveType(GLenum mode, GLsizei count, bool usesPointSi
return count >= minCount;
}
-void Renderer11::unsetConflictingSRVs(gl::SamplerType samplerType, uintptr_t resource, const gl::ImageIndex *index)
+gl::Error Renderer11::applyRenderTarget(const gl::Framebuffer *framebuffer)
{
- auto &currentSRVs = (samplerType == gl::SAMPLER_VERTEX ? mCurVertexSRVs : mCurPixelSRVs);
-
- for (size_t resourceIndex = 0; resourceIndex < currentSRVs.size(); ++resourceIndex)
- {
- auto &record = currentSRVs[resourceIndex];
-
- if (record.srv && record.resource == resource && ImageIndexConflictsWithSRV(index, record.desc))
- {
- setShaderResource(samplerType, static_cast<UINT>(resourceIndex), NULL);
- }
- }
+ return mStateManager.syncFramebuffer(framebuffer);
}
-gl::Error Renderer11::applyRenderTarget(const gl::Framebuffer *framebuffer)
+gl::Error Renderer11::applyVertexBuffer(const gl::State &state,
+ GLenum mode,
+ GLint first,
+ GLsizei count,
+ GLsizei instances,
+ TranslatedIndexData *indexInfo)
{
- // Get the color render buffer and serial
- // Also extract the render target dimensions and view
- unsigned int renderTargetWidth = 0;
- unsigned int renderTargetHeight = 0;
- DXGI_FORMAT renderTargetFormat = DXGI_FORMAT_UNKNOWN;
- ID3D11RenderTargetView* framebufferRTVs[gl::IMPLEMENTATION_MAX_DRAW_BUFFERS] = {NULL};
- bool missingColorRenderTarget = true;
-
- const FramebufferD3D *framebufferD3D = GetImplAs<FramebufferD3D>(framebuffer);
- const gl::AttachmentList &colorbuffers = framebufferD3D->getColorAttachmentsForRender(getWorkarounds());
-
- for (size_t colorAttachment = 0; colorAttachment < colorbuffers.size(); ++colorAttachment)
- {
- gl::FramebufferAttachment *colorbuffer = colorbuffers[colorAttachment];
-
- if (colorbuffer)
- {
- // the draw buffer must be either "none", "back" for the default buffer or the same index as this color (in order)
-
- // check for zero-sized default framebuffer, which is a special case.
- // in this case we do not wish to modify any state and just silently return false.
- // this will not report any gl error but will cause the calling method to return.
- if (colorbuffer->getWidth() == 0 || colorbuffer->getHeight() == 0)
- {
- return gl::Error(GL_NO_ERROR);
- }
-
- // Extract the render target dimensions and view
- RenderTarget11 *renderTarget = NULL;
- gl::Error error = d3d11::GetAttachmentRenderTarget(colorbuffer, &renderTarget);
- if (error.isError())
- {
- return error;
- }
- ASSERT(renderTarget);
-
- framebufferRTVs[colorAttachment] = renderTarget->getRenderTargetView();
- ASSERT(framebufferRTVs[colorAttachment]);
-
- if (missingColorRenderTarget)
- {
- renderTargetWidth = renderTarget->getWidth();
- renderTargetHeight = renderTarget->getHeight();
- renderTargetFormat = renderTarget->getDXGIFormat();
- missingColorRenderTarget = false;
- }
-
- // Unbind render target SRVs from the shader here to prevent D3D11 warnings.
- if (colorbuffer->type() == GL_TEXTURE)
- {
- uintptr_t rtResource = reinterpret_cast<uintptr_t>(GetViewResource(framebufferRTVs[colorAttachment]));
- const gl::ImageIndex *index = colorbuffer->getTextureImageIndex();
- ASSERT(index);
- // The index doesn't need to be corrected for the small compressed texture workaround
- // because a rendertarget is never compressed.
- unsetConflictingSRVs(gl::SAMPLER_VERTEX, rtResource, index);
- unsetConflictingSRVs(gl::SAMPLER_PIXEL, rtResource, index);
- }
- }
- }
-
- // Get the depth stencil buffers
- ID3D11DepthStencilView* framebufferDSV = NULL;
- gl::FramebufferAttachment *depthStencil = framebuffer->getDepthOrStencilbuffer();
- if (depthStencil)
- {
- RenderTarget11 *depthStencilRenderTarget = NULL;
- gl::Error error = d3d11::GetAttachmentRenderTarget(depthStencil, &depthStencilRenderTarget);
- if (error.isError())
- {
- SafeRelease(framebufferRTVs);
- return error;
- }
- ASSERT(depthStencilRenderTarget);
-
- framebufferDSV = depthStencilRenderTarget->getDepthStencilView();
- ASSERT(framebufferDSV);
-
- // If there is no render buffer, the width, height and format values come from
- // the depth stencil
- if (missingColorRenderTarget)
- {
- renderTargetWidth = depthStencilRenderTarget->getWidth();
- renderTargetHeight = depthStencilRenderTarget->getHeight();
- renderTargetFormat = depthStencilRenderTarget->getDXGIFormat();
- }
-
- // Unbind render target SRVs from the shader here to prevent D3D11 warnings.
- if (depthStencil->type() == GL_TEXTURE)
- {
- uintptr_t depthStencilResource = reinterpret_cast<uintptr_t>(GetViewResource(framebufferDSV));
- const gl::ImageIndex *index = depthStencil->getTextureImageIndex();
- ASSERT(index);
- // The index doesn't need to be corrected for the small compressed texture workaround
- // because a rendertarget is never compressed.
- unsetConflictingSRVs(gl::SAMPLER_VERTEX, depthStencilResource, index);
- unsetConflictingSRVs(gl::SAMPLER_PIXEL, depthStencilResource, index);
- }
- }
-
- // Apply the render target and depth stencil
- if (!mRenderTargetDescInitialized || !mDepthStencilInitialized ||
- memcmp(framebufferRTVs, mAppliedRTVs, sizeof(framebufferRTVs)) != 0 ||
- reinterpret_cast<uintptr_t>(framebufferDSV) != mAppliedDSV)
- {
- mDeviceContext->OMSetRenderTargets(getRendererCaps().maxDrawBuffers, framebufferRTVs, framebufferDSV);
-
- mRenderTargetDesc.width = renderTargetWidth;
- mRenderTargetDesc.height = renderTargetHeight;
- mRenderTargetDesc.format = renderTargetFormat;
- mForceSetViewport = true;
- mForceSetScissor = true;
- mForceSetBlendState = true;
-
- if (!mDepthStencilInitialized)
- {
- mForceSetRasterState = true;
- }
-
- for (size_t rtIndex = 0; rtIndex < ArraySize(framebufferRTVs); rtIndex++)
- {
- mAppliedRTVs[rtIndex] = reinterpret_cast<uintptr_t>(framebufferRTVs[rtIndex]);
- }
- mAppliedDSV = reinterpret_cast<uintptr_t>(framebufferDSV);
- mRenderTargetDescInitialized = true;
- mDepthStencilInitialized = true;
- }
-
- const Framebuffer11 *framebuffer11 = GetImplAs<Framebuffer11>(framebuffer);
- gl::Error error = framebuffer11->invalidateSwizzles();
+ gl::Error error = mVertexDataManager->prepareVertexData(state, first, count, &mTranslatedAttribCache, instances);
if (error.isError())
{
return error;
}
- return gl::Error(GL_NO_ERROR);
-}
-
-gl::Error Renderer11::applyVertexBuffer(const gl::State &state, GLenum mode, GLint first, GLsizei count, GLsizei instances)
-{
- TranslatedAttribute attributes[gl::MAX_VERTEX_ATTRIBS];
- gl::Error error = mVertexDataManager->prepareVertexData(state, first, count, attributes, instances);
- if (error.isError())
+ // If index information is passed, mark it with the current changed status.
+ if (indexInfo)
{
- return error;
+ indexInfo->srcIndexData.srcIndicesChanged = mAppliedIBChanged;
}
- return mInputLayoutCache.applyVertexBuffers(attributes, mode, state.getProgram());
+ GLsizei numIndicesPerInstance = 0;
+ if (instances > 0)
+ {
+ numIndicesPerInstance = count;
+ }
+ return mInputLayoutCache.applyVertexBuffers(mTranslatedAttribCache, mode, state.getProgram(),
+ indexInfo, numIndicesPerInstance);
}
-gl::Error Renderer11::applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo)
+gl::Error Renderer11::applyIndexBuffer(const gl::Data &data,
+ const GLvoid *indices,
+ GLsizei count,
+ GLenum mode,
+ GLenum type,
+ TranslatedIndexData *indexInfo)
{
- gl::Error error = mIndexDataManager->prepareIndexData(type, count, elementArrayBuffer, indices, indexInfo);
+ gl::VertexArray *vao = data.state->getVertexArray();
+ gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
+ gl::Error error =
+ mIndexDataManager->prepareIndexData(type, count, elementArrayBuffer, indices, indexInfo,
+ data.state->isPrimitiveRestartEnabled());
if (error.isError())
{
return error;
@@ -1447,15 +1565,16 @@ gl::Error Renderer11::applyIndexBuffer(const GLvoid *indices, gl::Buffer *elemen
if (indexInfo->storage)
{
- Buffer11 *storage = Buffer11::makeBuffer11(indexInfo->storage);
+ Buffer11 *storage = GetAs<Buffer11>(indexInfo->storage);
buffer = storage->getBuffer(BUFFER_USAGE_INDEX);
}
else
{
- IndexBuffer11* indexBuffer = IndexBuffer11::makeIndexBuffer11(indexInfo->indexBuffer);
+ IndexBuffer11* indexBuffer = GetAs<IndexBuffer11>(indexInfo->indexBuffer);
buffer = indexBuffer->getBuffer();
}
+ mAppliedIBChanged = false;
if (buffer != mAppliedIB || bufferFormat != mAppliedIBFormat || indexInfo->startOffset != mAppliedIBOffset)
{
mDeviceContext->IASetIndexBuffer(buffer, bufferFormat, indexInfo->startOffset);
@@ -1463,6 +1582,7 @@ gl::Error Renderer11::applyIndexBuffer(const GLvoid *indices, gl::Buffer *elemen
mAppliedIB = buffer;
mAppliedIBFormat = bufferFormat;
mAppliedIBOffset = indexInfo->startOffset;
+ mAppliedIBChanged = true;
}
return gl::Error(GL_NO_ERROR);
@@ -1475,22 +1595,23 @@ void Renderer11::applyTransformFeedbackBuffers(const gl::State &state)
if (state.isTransformFeedbackActiveUnpaused())
{
- numXFBBindings = state.getTransformFeedbackBufferIndexRange();
+ const gl::TransformFeedback *transformFeedback = state.getCurrentTransformFeedback();
+ numXFBBindings = transformFeedback->getIndexedBufferCount();
ASSERT(numXFBBindings <= gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS);
for (size_t i = 0; i < numXFBBindings; i++)
{
- gl::Buffer *curXFBBuffer = state.getIndexedTransformFeedbackBuffer(i);
- GLintptr curXFBOffset = state.getIndexedTransformFeedbackBufferOffset(i);
+ const OffsetBindingPointer<gl::Buffer> &binding = transformFeedback->getIndexedBuffer(i);
+
ID3D11Buffer *d3dBuffer = NULL;
- if (curXFBBuffer)
+ if (binding.get() != nullptr)
{
- Buffer11 *storage = Buffer11::makeBuffer11(curXFBBuffer->getImplementation());
+ Buffer11 *storage = GetImplAs<Buffer11>(binding.get());
d3dBuffer = storage->getBuffer(BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK);
}
// TODO: mAppliedTFBuffers and friends should also be kept in a vector.
- if (d3dBuffer != mAppliedTFBuffers[i] || curXFBOffset != mAppliedTFOffsets[i])
+ if (d3dBuffer != mAppliedTFBuffers[i] || binding.getOffset() != mAppliedTFOffsets[i])
{
requiresUpdate = true;
}
@@ -1499,18 +1620,17 @@ void Renderer11::applyTransformFeedbackBuffers(const gl::State &state)
if (requiresUpdate || numXFBBindings != mAppliedNumXFBBindings)
{
+ const gl::TransformFeedback *transformFeedback = state.getCurrentTransformFeedback();
for (size_t i = 0; i < numXFBBindings; ++i)
{
- gl::Buffer *curXFBBuffer = state.getIndexedTransformFeedbackBuffer(i);
- GLintptr curXFBOffset = state.getIndexedTransformFeedbackBufferOffset(i);
-
- if (curXFBBuffer)
+ const OffsetBindingPointer<gl::Buffer> &binding = transformFeedback->getIndexedBuffer(i);
+ if (binding.get() != nullptr)
{
- Buffer11 *storage = Buffer11::makeBuffer11(curXFBBuffer->getImplementation());
+ Buffer11 *storage = GetImplAs<Buffer11>(binding.get());
ID3D11Buffer *d3dBuffer = storage->getBuffer(BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK);
- mCurrentD3DOffsets[i] = (mAppliedTFBuffers[i] != d3dBuffer || mAppliedTFOffsets[i] != curXFBOffset) ?
- static_cast<UINT>(curXFBOffset) : -1;
+ mCurrentD3DOffsets[i] = (mAppliedTFBuffers[i] != d3dBuffer || mAppliedTFOffsets[i] != binding.getOffset()) ?
+ static_cast<UINT>(binding.getOffset()) : -1;
mAppliedTFBuffers[i] = d3dBuffer;
}
else
@@ -1518,26 +1638,30 @@ void Renderer11::applyTransformFeedbackBuffers(const gl::State &state)
mAppliedTFBuffers[i] = NULL;
mCurrentD3DOffsets[i] = 0;
}
- mAppliedTFOffsets[i] = curXFBOffset;
+ mAppliedTFOffsets[i] = binding.getOffset();
}
mAppliedNumXFBBindings = numXFBBindings;
- mDeviceContext->SOSetTargets(numXFBBindings, mAppliedTFBuffers, mCurrentD3DOffsets);
+ mDeviceContext->SOSetTargets(static_cast<unsigned int>(numXFBBindings), mAppliedTFBuffers,
+ mCurrentD3DOffsets);
}
}
-gl::Error Renderer11::drawArrays(const gl::Data &data, GLenum mode, GLsizei count, GLsizei instances, bool usesPointSize)
+gl::Error Renderer11::drawArraysImpl(const gl::Data &data,
+ GLenum mode,
+ GLsizei count,
+ GLsizei instances)
{
- bool useInstancedPointSpriteEmulation = usesPointSize && getWorkarounds().useInstancedPointSpriteEmulation;
- if (mode == GL_POINTS && data.state->isTransformFeedbackActiveUnpaused())
- {
- // Since point sprites are generated with a geometry shader, too many vertices will
- // be written if transform feedback is active. To work around this, draw only the points
- // with the stream out shader and no pixel shader to feed the stream out buffers and then
- // draw again with the point sprite geometry shader to rasterize the point sprites.
+ ProgramD3D *programD3D = GetImplAs<ProgramD3D>(data.state->getProgram());
- mDeviceContext->PSSetShader(NULL, NULL, 0);
+ if (programD3D->usesGeometryShader(mode) && data.state->isTransformFeedbackActiveUnpaused())
+ {
+ // Since we use a geometry if-and-only-if we rewrite vertex streams, transform feedback
+ // won't get the correct output. To work around this, draw with *only* the stream out
+ // first (no pixel shader) to feed the stream out buffers and then draw again with the
+ // geometry shader + pixel shader to rasterize the primitives.
+ mDeviceContext->PSSetShader(nullptr, nullptr, 0);
if (instances > 0)
{
@@ -1548,98 +1672,192 @@ gl::Error Renderer11::drawArrays(const gl::Data &data, GLenum mode, GLsizei coun
mDeviceContext->Draw(count, 0);
}
- ProgramD3D *programD3D = GetImplAs<ProgramD3D>(data.state->getProgram());
-
- rx::ShaderExecutableD3D *pixelExe = NULL;
+ rx::ShaderExecutableD3D *pixelExe = nullptr;
gl::Error error = programD3D->getPixelExecutableForFramebuffer(data.state->getDrawFramebuffer(), &pixelExe);
if (error.isError())
{
return error;
}
- // Skip this step if we're doing rasterizer discard.
- if (pixelExe && !data.state->getRasterizerState().rasterizerDiscard && usesPointSize)
+ // Skip the draw call if rasterizer discard is enabled (or no fragment shader).
+ if (!pixelExe || data.state->getRasterizerState().rasterizerDiscard)
{
- ID3D11PixelShader *pixelShader = ShaderExecutable11::makeShaderExecutable11(pixelExe)->getPixelShader();
- ASSERT(reinterpret_cast<uintptr_t>(pixelShader) == mAppliedPixelShader);
- mDeviceContext->PSSetShader(pixelShader, NULL, 0);
+ return gl::Error(GL_NO_ERROR);
+ }
- // Retrieve the point sprite geometry shader
- rx::ShaderExecutableD3D *geometryExe = programD3D->getGeometryExecutable();
- ID3D11GeometryShader *geometryShader = (geometryExe ? ShaderExecutable11::makeShaderExecutable11(geometryExe)->getGeometryShader() : NULL);
- mAppliedGeometryShader = reinterpret_cast<uintptr_t>(geometryShader);
- ASSERT(geometryShader);
- mDeviceContext->GSSetShader(geometryShader, NULL, 0);
+ ID3D11PixelShader *pixelShader = GetAs<ShaderExecutable11>(pixelExe)->getPixelShader();
+ ASSERT(reinterpret_cast<uintptr_t>(pixelShader) == mAppliedPixelShader);
+ mDeviceContext->PSSetShader(pixelShader, NULL, 0);
- if (instances > 0)
- {
- mDeviceContext->DrawInstanced(count, instances, 0, 0);
- }
- else
- {
- mDeviceContext->Draw(count, 0);
- }
+ // Retrieve the geometry shader.
+ rx::ShaderExecutableD3D *geometryExe = nullptr;
+ error =
+ programD3D->getGeometryExecutableForPrimitiveType(data, mode, &geometryExe, nullptr);
+ if (error.isError())
+ {
+ return error;
}
+ ID3D11GeometryShader *geometryShader =
+ (geometryExe ? GetAs<ShaderExecutable11>(geometryExe)->getGeometryShader() : NULL);
+ mAppliedGeometryShader = reinterpret_cast<uintptr_t>(geometryShader);
+ ASSERT(geometryShader);
+ mDeviceContext->GSSetShader(geometryShader, NULL, 0);
+
+ if (instances > 0)
+ {
+ mDeviceContext->DrawInstanced(count, instances, 0, 0);
+ }
+ else
+ {
+ mDeviceContext->Draw(count, 0);
+ }
return gl::Error(GL_NO_ERROR);
}
- else if (mode == GL_LINE_LOOP)
- {
- return drawLineLoop(count, GL_NONE, NULL, 0, NULL);
- }
- else if (mode == GL_TRIANGLE_FAN)
+
+ if (mode == GL_LINE_LOOP)
{
- return drawTriangleFan(count, GL_NONE, NULL, 0, NULL, instances);
+ return drawLineLoop(data, count, GL_NONE, nullptr, nullptr, instances);
}
- else if (instances > 0)
+
+ if (mode == GL_TRIANGLE_FAN)
{
- mDeviceContext->DrawInstanced(count, instances, 0, 0);
- return gl::Error(GL_NO_ERROR);
+ return drawTriangleFan(data, count, GL_NONE, nullptr, 0, instances);
}
- else
+
+ bool useInstancedPointSpriteEmulation =
+ programD3D->usesPointSize() && getWorkarounds().useInstancedPointSpriteEmulation;
+
+ if (instances > 0)
{
- // If gl_PointSize is used and GL_POINTS is specified, then it is expected to render pointsprites.
- // If instanced pointsprite emulation is being used the topology is expexted to be
- // D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST and DrawIndexedInstanced must be used.
if (mode == GL_POINTS && useInstancedPointSpriteEmulation)
{
- mDeviceContext->DrawIndexedInstanced(6, count, 0, 0, 0);
+ // If pointsprite emulation is used with glDrawArraysInstanced then we need to take a
+ // less efficent code path.
+ // Instanced rendering of emulated pointsprites requires a loop to draw each batch of
+ // points. An offset into the instanced data buffer is calculated and applied on each
+ // iteration to ensure all instances are rendered correctly.
+
+ // Each instance being rendered requires the inputlayout cache to reapply buffers and
+ // offsets.
+ for (GLsizei i = 0; i < instances; i++)
+ {
+ gl::Error error = mInputLayoutCache.updateVertexOffsetsForPointSpritesEmulation(i);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ mDeviceContext->DrawIndexedInstanced(6, count, 0, 0, 0);
+ }
}
else
{
- mDeviceContext->Draw(count, 0);
+ mDeviceContext->DrawInstanced(count, instances, 0, 0);
}
return gl::Error(GL_NO_ERROR);
}
+
+ // If the shader is writing to gl_PointSize, then pointsprites are being rendered.
+ // Emulating instanced point sprites for FL9_3 requires the topology to be
+ // D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST and DrawIndexedInstanced is called instead.
+ if (mode == GL_POINTS && useInstancedPointSpriteEmulation)
+ {
+ mDeviceContext->DrawIndexedInstanced(6, count, 0, 0, 0);
+ }
+ else
+ {
+ mDeviceContext->Draw(count, 0);
+ }
+ return gl::Error(GL_NO_ERROR);
}
-gl::Error Renderer11::drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices,
- gl::Buffer *elementArrayBuffer, const TranslatedIndexData &indexInfo, GLsizei instances)
+gl::Error Renderer11::drawElementsImpl(const gl::Data &data,
+ const TranslatedIndexData &indexInfo,
+ GLenum mode,
+ GLsizei count,
+ GLenum type,
+ const GLvoid *indices,
+ GLsizei instances)
{
int minIndex = static_cast<int>(indexInfo.indexRange.start);
if (mode == GL_LINE_LOOP)
{
- return drawLineLoop(count, type, indices, minIndex, elementArrayBuffer);
+ return drawLineLoop(data, count, type, indices, &indexInfo, instances);
}
- else if (mode == GL_TRIANGLE_FAN)
+
+ if (mode == GL_TRIANGLE_FAN)
{
- return drawTriangleFan(count, type, indices, minIndex, elementArrayBuffer, instances);
+ return drawTriangleFan(data, count, type, indices, minIndex, instances);
}
- else if (instances > 0)
+
+ const ProgramD3D *programD3D = GetImplAs<ProgramD3D>(data.state->getProgram());
+ if (instances > 0)
{
- mDeviceContext->DrawIndexedInstanced(count, instances, 0, -minIndex, 0);
+ if (mode == GL_POINTS && programD3D->usesInstancedPointSpriteEmulation())
+ {
+ // If pointsprite emulation is used with glDrawElementsInstanced then we need to take a
+ // less efficent code path.
+ // Instanced rendering of emulated pointsprites requires a loop to draw each batch of
+ // points. An offset into the instanced data buffer is calculated and applied on each
+ // iteration to ensure all instances are rendered correctly.
+ GLsizei elementsToRender = static_cast<GLsizei>(indexInfo.indexRange.vertexCount());
+
+ // Each instance being rendered requires the inputlayout cache to reapply buffers and
+ // offsets.
+ for (GLsizei i = 0; i < instances; i++)
+ {
+ gl::Error error = mInputLayoutCache.updateVertexOffsetsForPointSpritesEmulation(i);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ mDeviceContext->DrawIndexedInstanced(6, elementsToRender, 0, 0, 0);
+ }
+ }
+ else
+ {
+ mDeviceContext->DrawIndexedInstanced(count, instances, 0, -minIndex, 0);
+ }
return gl::Error(GL_NO_ERROR);
}
+
+ // If the shader is writing to gl_PointSize, then pointsprites are being rendered.
+ // Emulating instanced point sprites for FL9_3 requires the topology to be
+ // D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST and DrawIndexedInstanced is called instead.
+ if (mode == GL_POINTS && programD3D->usesInstancedPointSpriteEmulation())
+ {
+ // The count parameter passed to drawElements represents the total number of instances
+ // to be rendered. Each instance is referenced by the bound index buffer from the
+ // the caller.
+ //
+ // Indexed pointsprite emulation replicates data for duplicate entries found
+ // in the index buffer.
+ // This is not an efficent rendering mechanism and is only used on downlevel renderers
+ // that do not support geometry shaders.
+ mDeviceContext->DrawIndexedInstanced(6, count, 0, 0, 0);
+ }
else
{
mDeviceContext->DrawIndexed(count, 0, -minIndex);
- return gl::Error(GL_NO_ERROR);
}
+ return gl::Error(GL_NO_ERROR);
}
-gl::Error Renderer11::drawLineLoop(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer)
+gl::Error Renderer11::drawLineLoop(const gl::Data &data,
+ GLsizei count,
+ GLenum type,
+ const GLvoid *indexPointer,
+ const TranslatedIndexData *indexInfo,
+ int instances)
{
+ gl::VertexArray *vao = data.state->getVertexArray();
+ gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
+
+ const GLvoid *indices = indexPointer;
+
// Get the raw indices for an indexed draw
if (type != GL_NONE && elementArrayBuffer)
{
@@ -1675,7 +1893,11 @@ gl::Error Renderer11::drawLineLoop(GLsizei count, GLenum type, const GLvoid *ind
return gl::Error(GL_OUT_OF_MEMORY, "Failed to create a 32-bit looping index buffer for GL_LINE_LOOP, too many indices required.");
}
- const unsigned int spaceNeeded = (static_cast<unsigned int>(count) + 1) * sizeof(unsigned int);
+ GetLineLoopIndices(indices, type, static_cast<GLuint>(count),
+ data.state->isPrimitiveRestartEnabled(), &mScratchIndexDataBuffer);
+
+ unsigned int spaceNeeded =
+ static_cast<unsigned int>(sizeof(GLuint) * mScratchIndexDataBuffer.size());
gl::Error error = mLineLoopIB->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_INT);
if (error.isError())
{
@@ -1690,41 +1912,9 @@ gl::Error Renderer11::drawLineLoop(GLsizei count, GLenum type, const GLvoid *ind
return error;
}
- unsigned int *data = reinterpret_cast<unsigned int*>(mappedMemory);
- unsigned int indexBufferOffset = offset;
-
- switch (type)
- {
- case GL_NONE: // Non-indexed draw
- for (int i = 0; i < count; i++)
- {
- data[i] = i;
- }
- data[count] = 0;
- break;
- case GL_UNSIGNED_BYTE:
- for (int i = 0; i < count; i++)
- {
- data[i] = static_cast<const GLubyte*>(indices)[i];
- }
- data[count] = static_cast<const GLubyte*>(indices)[0];
- break;
- case GL_UNSIGNED_SHORT:
- for (int i = 0; i < count; i++)
- {
- data[i] = static_cast<const GLushort*>(indices)[i];
- }
- data[count] = static_cast<const GLushort*>(indices)[0];
- break;
- case GL_UNSIGNED_INT:
- for (int i = 0; i < count; i++)
- {
- data[i] = static_cast<const GLuint*>(indices)[i];
- }
- data[count] = static_cast<const GLuint*>(indices)[0];
- break;
- default: UNREACHABLE();
- }
+ // Copy over the converted index data.
+ memcpy(mappedMemory, &mScratchIndexDataBuffer[0],
+ sizeof(GLuint) * mScratchIndexDataBuffer.size());
error = mLineLoopIB->unmapBuffer();
if (error.isError())
@@ -1732,25 +1922,46 @@ gl::Error Renderer11::drawLineLoop(GLsizei count, GLenum type, const GLvoid *ind
return error;
}
- IndexBuffer11 *indexBuffer = IndexBuffer11::makeIndexBuffer11(mLineLoopIB->getIndexBuffer());
+ IndexBuffer11 *indexBuffer = GetAs<IndexBuffer11>(mLineLoopIB->getIndexBuffer());
ID3D11Buffer *d3dIndexBuffer = indexBuffer->getBuffer();
DXGI_FORMAT indexFormat = indexBuffer->getIndexFormat();
- if (mAppliedIB != d3dIndexBuffer || mAppliedIBFormat != indexFormat || mAppliedIBOffset != indexBufferOffset)
+ if (mAppliedIB != d3dIndexBuffer || mAppliedIBFormat != indexFormat ||
+ mAppliedIBOffset != offset)
{
- mDeviceContext->IASetIndexBuffer(d3dIndexBuffer, indexFormat, indexBufferOffset);
+ mDeviceContext->IASetIndexBuffer(d3dIndexBuffer, indexFormat, offset);
mAppliedIB = d3dIndexBuffer;
mAppliedIBFormat = indexFormat;
- mAppliedIBOffset = indexBufferOffset;
+ mAppliedIBOffset = offset;
}
- mDeviceContext->DrawIndexed(count + 1, 0, -minIndex);
+ INT baseVertexLocation = (indexInfo ? -static_cast<int>(indexInfo->indexRange.start) : 0);
+ UINT indexCount = static_cast<UINT>(mScratchIndexDataBuffer.size());
+
+ if (instances > 0)
+ {
+ mDeviceContext->DrawIndexedInstanced(indexCount, instances, 0, baseVertexLocation, 0);
+ }
+ else
+ {
+ mDeviceContext->DrawIndexed(indexCount, 0, baseVertexLocation);
+ }
return gl::Error(GL_NO_ERROR);
}
-gl::Error Renderer11::drawTriangleFan(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer, int instances)
+gl::Error Renderer11::drawTriangleFan(const gl::Data &data,
+ GLsizei count,
+ GLenum type,
+ const GLvoid *indices,
+ int minIndex,
+ int instances)
{
+ gl::VertexArray *vao = data.state->getVertexArray();
+ gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
+
+ const GLvoid *indexPointer = indices;
+
// Get the raw indices for an indexed draw
if (type != GL_NONE && elementArrayBuffer)
{
@@ -1764,7 +1975,7 @@ gl::Error Renderer11::drawTriangleFan(GLsizei count, GLenum type, const GLvoid *
return error;
}
- indices = bufferData + offset;
+ indexPointer = bufferData + offset;
}
if (!mTriangleFanIB)
@@ -1781,21 +1992,25 @@ gl::Error Renderer11::drawTriangleFan(GLsizei count, GLenum type, const GLvoid *
// Checked by Renderer11::applyPrimitiveType
ASSERT(count >= 3);
- const unsigned int numTris = count - 2;
+ const GLuint numTris = count - 2;
if (numTris > (std::numeric_limits<unsigned int>::max() / (sizeof(unsigned int) * 3)))
{
return gl::Error(GL_OUT_OF_MEMORY, "Failed to create a scratch index buffer for GL_TRIANGLE_FAN, too many indices required.");
}
- const unsigned int spaceNeeded = (numTris * 3) * sizeof(unsigned int);
+ GetTriFanIndices(indexPointer, type, count, data.state->isPrimitiveRestartEnabled(),
+ &mScratchIndexDataBuffer);
+
+ const unsigned int spaceNeeded =
+ static_cast<unsigned int>(mScratchIndexDataBuffer.size() * sizeof(unsigned int));
gl::Error error = mTriangleFanIB->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_INT);
if (error.isError())
{
return error;
}
- void* mappedMemory = NULL;
+ void *mappedMemory = nullptr;
unsigned int offset;
error = mTriangleFanIB->mapBuffer(spaceNeeded, &mappedMemory, &offset);
if (error.isError())
@@ -1803,45 +2018,7 @@ gl::Error Renderer11::drawTriangleFan(GLsizei count, GLenum type, const GLvoid *
return error;
}
- unsigned int *data = reinterpret_cast<unsigned int*>(mappedMemory);
- unsigned int indexBufferOffset = offset;
-
- switch (type)
- {
- case GL_NONE: // Non-indexed draw
- for (unsigned int i = 0; i < numTris; i++)
- {
- data[i*3 + 0] = 0;
- data[i*3 + 1] = i + 1;
- data[i*3 + 2] = i + 2;
- }
- break;
- case GL_UNSIGNED_BYTE:
- for (unsigned int i = 0; i < numTris; i++)
- {
- data[i*3 + 0] = static_cast<const GLubyte*>(indices)[0];
- data[i*3 + 1] = static_cast<const GLubyte*>(indices)[i + 1];
- data[i*3 + 2] = static_cast<const GLubyte*>(indices)[i + 2];
- }
- break;
- case GL_UNSIGNED_SHORT:
- for (unsigned int i = 0; i < numTris; i++)
- {
- data[i*3 + 0] = static_cast<const GLushort*>(indices)[0];
- data[i*3 + 1] = static_cast<const GLushort*>(indices)[i + 1];
- data[i*3 + 2] = static_cast<const GLushort*>(indices)[i + 2];
- }
- break;
- case GL_UNSIGNED_INT:
- for (unsigned int i = 0; i < numTris; i++)
- {
- data[i*3 + 0] = static_cast<const GLuint*>(indices)[0];
- data[i*3 + 1] = static_cast<const GLuint*>(indices)[i + 1];
- data[i*3 + 2] = static_cast<const GLuint*>(indices)[i + 2];
- }
- break;
- default: UNREACHABLE();
- }
+ memcpy(mappedMemory, &mScratchIndexDataBuffer[0], spaceNeeded);
error = mTriangleFanIB->unmapBuffer();
if (error.isError())
@@ -1849,34 +2026,37 @@ gl::Error Renderer11::drawTriangleFan(GLsizei count, GLenum type, const GLvoid *
return error;
}
- IndexBuffer11 *indexBuffer = IndexBuffer11::makeIndexBuffer11(mTriangleFanIB->getIndexBuffer());
+ IndexBuffer11 *indexBuffer = GetAs<IndexBuffer11>(mTriangleFanIB->getIndexBuffer());
ID3D11Buffer *d3dIndexBuffer = indexBuffer->getBuffer();
DXGI_FORMAT indexFormat = indexBuffer->getIndexFormat();
- if (mAppliedIB != d3dIndexBuffer || mAppliedIBFormat != indexFormat || mAppliedIBOffset != indexBufferOffset)
+ if (mAppliedIB != d3dIndexBuffer || mAppliedIBFormat != indexFormat ||
+ mAppliedIBOffset != offset)
{
- mDeviceContext->IASetIndexBuffer(d3dIndexBuffer, indexFormat, indexBufferOffset);
+ mDeviceContext->IASetIndexBuffer(d3dIndexBuffer, indexFormat, offset);
mAppliedIB = d3dIndexBuffer;
mAppliedIBFormat = indexFormat;
- mAppliedIBOffset = indexBufferOffset;
+ mAppliedIBOffset = offset;
}
+ UINT indexCount = static_cast<UINT>(mScratchIndexDataBuffer.size());
+
if (instances > 0)
{
- mDeviceContext->DrawIndexedInstanced(numTris * 3, instances, 0, -minIndex, 0);
+ mDeviceContext->DrawIndexedInstanced(indexCount, instances, 0, -minIndex, 0);
}
else
{
- mDeviceContext->DrawIndexed(numTris * 3, 0, -minIndex);
+ mDeviceContext->DrawIndexed(indexCount, 0, -minIndex);
}
return gl::Error(GL_NO_ERROR);
}
-gl::Error Renderer11::applyShaders(gl::Program *program, const gl::VertexFormat inputLayout[], const gl::Framebuffer *framebuffer,
- bool rasterizerDiscard, bool transformFeedbackActive)
+gl::Error Renderer11::applyShadersImpl(const gl::Data &data, GLenum drawMode)
{
- ProgramD3D *programD3D = GetImplAs<ProgramD3D>(program);
+ ProgramD3D *programD3D = GetImplAs<ProgramD3D>(data.state->getProgram());
+ const auto &inputLayout = programD3D->getCachedInputLayout();
ShaderExecutableD3D *vertexExe = NULL;
gl::Error error = programD3D->getVertexExecutableForInputLayout(inputLayout, &vertexExe, nullptr);
@@ -1885,32 +2065,41 @@ gl::Error Renderer11::applyShaders(gl::Program *program, const gl::VertexFormat
return error;
}
+ const gl::Framebuffer *drawFramebuffer = data.state->getDrawFramebuffer();
ShaderExecutableD3D *pixelExe = NULL;
- error = programD3D->getPixelExecutableForFramebuffer(framebuffer, &pixelExe);
+ error = programD3D->getPixelExecutableForFramebuffer(drawFramebuffer, &pixelExe);
if (error.isError())
{
return error;
}
- ShaderExecutableD3D *geometryExe = programD3D->getGeometryExecutable();
+ ShaderExecutableD3D *geometryExe = nullptr;
+ error =
+ programD3D->getGeometryExecutableForPrimitiveType(data, drawMode, &geometryExe, nullptr);
+ if (error.isError())
+ {
+ return error;
+ }
- ID3D11VertexShader *vertexShader = (vertexExe ? ShaderExecutable11::makeShaderExecutable11(vertexExe)->getVertexShader() : NULL);
+ ID3D11VertexShader *vertexShader = (vertexExe ? GetAs<ShaderExecutable11>(vertexExe)->getVertexShader() : NULL);
ID3D11PixelShader *pixelShader = NULL;
// Skip pixel shader if we're doing rasterizer discard.
+ bool rasterizerDiscard = data.state->getRasterizerState().rasterizerDiscard;
if (!rasterizerDiscard)
{
- pixelShader = (pixelExe ? ShaderExecutable11::makeShaderExecutable11(pixelExe)->getPixelShader() : NULL);
+ pixelShader = (pixelExe ? GetAs<ShaderExecutable11>(pixelExe)->getPixelShader() : NULL);
}
ID3D11GeometryShader *geometryShader = NULL;
+ bool transformFeedbackActive = data.state->isTransformFeedbackActiveUnpaused();
if (transformFeedbackActive)
{
- geometryShader = (vertexExe ? ShaderExecutable11::makeShaderExecutable11(vertexExe)->getStreamOutShader() : NULL);
+ geometryShader = (vertexExe ? GetAs<ShaderExecutable11>(vertexExe)->getStreamOutShader() : NULL);
}
- else if (mCurRasterState.pointDrawMode)
+ else
{
- geometryShader = (geometryExe ? ShaderExecutable11::makeShaderExecutable11(geometryExe)->getGeometryShader() : NULL);
+ geometryShader = (geometryExe ? GetAs<ShaderExecutable11>(geometryExe)->getGeometryShader() : NULL);
}
bool dirtyUniforms = false;
@@ -1944,7 +2133,9 @@ gl::Error Renderer11::applyShaders(gl::Program *program, const gl::VertexFormat
return gl::Error(GL_NO_ERROR);
}
-gl::Error Renderer11::applyUniforms(const ProgramImpl &program, const std::vector<gl::LinkedUniform*> &uniformArray)
+gl::Error Renderer11::applyUniforms(const ProgramD3D &programD3D,
+ GLenum drawMode,
+ const std::vector<D3DUniform *> &uniformArray)
{
unsigned int totalRegisterCountVS = 0;
unsigned int totalRegisterCountPS = 0;
@@ -1952,26 +2143,25 @@ gl::Error Renderer11::applyUniforms(const ProgramImpl &program, const std::vecto
bool vertexUniformsDirty = false;
bool pixelUniformsDirty = false;
- for (size_t uniformIndex = 0; uniformIndex < uniformArray.size(); uniformIndex++)
+ for (const D3DUniform *uniform : uniformArray)
{
- const gl::LinkedUniform &uniform = *uniformArray[uniformIndex];
-
- if (uniform.isReferencedByVertexShader() && !uniform.isSampler())
+ if (uniform->isReferencedByVertexShader() && !uniform->isSampler())
{
- totalRegisterCountVS += uniform.registerCount;
- vertexUniformsDirty = (vertexUniformsDirty || uniform.dirty);
+ totalRegisterCountVS += uniform->registerCount;
+ vertexUniformsDirty = (vertexUniformsDirty || uniform->dirty);
}
- if (uniform.isReferencedByFragmentShader() && !uniform.isSampler())
+ if (uniform->isReferencedByFragmentShader() && !uniform->isSampler())
{
- totalRegisterCountPS += uniform.registerCount;
- pixelUniformsDirty = (pixelUniformsDirty || uniform.dirty);
+ totalRegisterCountPS += uniform->registerCount;
+ pixelUniformsDirty = (pixelUniformsDirty || uniform->dirty);
}
}
- const ProgramD3D *programD3D = GetAs<ProgramD3D>(&program);
- const UniformStorage11 *vertexUniformStorage = UniformStorage11::makeUniformStorage11(&programD3D->getVertexUniformStorage());
- const UniformStorage11 *fragmentUniformStorage = UniformStorage11::makeUniformStorage11(&programD3D->getFragmentUniformStorage());
+ const UniformStorage11 *vertexUniformStorage =
+ GetAs<UniformStorage11>(&programD3D.getVertexUniformStorage());
+ const UniformStorage11 *fragmentUniformStorage =
+ GetAs<UniformStorage11>(&programD3D.getFragmentUniformStorage());
ASSERT(vertexUniformStorage);
ASSERT(fragmentUniformStorage);
@@ -1999,26 +2189,26 @@ gl::Error Renderer11::applyUniforms(const ProgramImpl &program, const std::vecto
mapPS = (float(*)[4])map.pData;
}
- for (size_t uniformIndex = 0; uniformIndex < uniformArray.size(); uniformIndex++)
+ for (const D3DUniform *uniform : uniformArray)
{
- gl::LinkedUniform *uniform = uniformArray[uniformIndex];
+ if (uniform->isSampler())
+ continue;
- if (!uniform->isSampler())
- {
- unsigned int componentCount = (4 - uniform->registerElement);
+ unsigned int componentCount = (4 - uniform->registerElement);
- // we assume that uniforms from structs are arranged in struct order in our uniforms list. otherwise we would
- // overwrite previously written regions of memory.
+ // we assume that uniforms from structs are arranged in struct order in our uniforms list.
+ // otherwise we would overwrite previously written regions of memory.
- if (uniform->isReferencedByVertexShader() && mapVS)
- {
- memcpy(&mapVS[uniform->vsRegisterIndex][uniform->registerElement], uniform->data, uniform->registerCount * sizeof(float) * componentCount);
- }
+ if (uniform->isReferencedByVertexShader() && mapVS)
+ {
+ memcpy(&mapVS[uniform->vsRegisterIndex][uniform->registerElement], uniform->data,
+ uniform->registerCount * sizeof(float) * componentCount);
+ }
- if (uniform->isReferencedByFragmentShader() && mapPS)
- {
- memcpy(&mapPS[uniform->psRegisterIndex][uniform->registerElement], uniform->data, uniform->registerCount * sizeof(float) * componentCount);
- }
+ if (uniform->isReferencedByFragmentShader() && mapPS)
+ {
+ memcpy(&mapPS[uniform->psRegisterIndex][uniform->registerElement], uniform->data,
+ uniform->registerCount * sizeof(float) * componentCount);
}
}
@@ -2048,7 +2238,7 @@ gl::Error Renderer11::applyUniforms(const ProgramImpl &program, const std::vecto
if (!mDriverConstantBufferVS)
{
D3D11_BUFFER_DESC constantBufferDescription = {0};
- constantBufferDescription.ByteWidth = sizeof(dx_VertexConstants);
+ constantBufferDescription.ByteWidth = sizeof(dx_VertexConstants11);
constantBufferDescription.Usage = D3D11_USAGE_DEFAULT;
constantBufferDescription.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
constantBufferDescription.CPUAccessFlags = 0;
@@ -2056,16 +2246,18 @@ gl::Error Renderer11::applyUniforms(const ProgramImpl &program, const std::vecto
constantBufferDescription.StructureByteStride = 0;
HRESULT result = mDevice->CreateBuffer(&constantBufferDescription, NULL, &mDriverConstantBufferVS);
- UNUSED_ASSERTION_VARIABLE(result);
ASSERT(SUCCEEDED(result));
-
+ if (FAILED(result))
+ {
+ return gl::Error(GL_OUT_OF_MEMORY, "Failed to create vertex shader constant buffer, result: 0x%X.", result);
+ }
mDeviceContext->VSSetConstantBuffers(1, 1, &mDriverConstantBufferVS);
}
if (!mDriverConstantBufferPS)
{
D3D11_BUFFER_DESC constantBufferDescription = {0};
- constantBufferDescription.ByteWidth = sizeof(dx_PixelConstants);
+ constantBufferDescription.ByteWidth = sizeof(dx_PixelConstants11);
constantBufferDescription.Usage = D3D11_USAGE_DEFAULT;
constantBufferDescription.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
constantBufferDescription.CPUAccessFlags = 0;
@@ -2073,32 +2265,50 @@ gl::Error Renderer11::applyUniforms(const ProgramImpl &program, const std::vecto
constantBufferDescription.StructureByteStride = 0;
HRESULT result = mDevice->CreateBuffer(&constantBufferDescription, NULL, &mDriverConstantBufferPS);
- UNUSED_ASSERTION_VARIABLE(result);
ASSERT(SUCCEEDED(result));
-
+ if (FAILED(result))
+ {
+ return gl::Error(GL_OUT_OF_MEMORY, "Failed to create pixel shader constant buffer, result: 0x%X.", result);
+ }
mDeviceContext->PSSetConstantBuffers(1, 1, &mDriverConstantBufferPS);
}
- if (memcmp(&mVertexConstants, &mAppliedVertexConstants, sizeof(dx_VertexConstants)) != 0)
+ const dx_VertexConstants11 &vertexConstants = mStateManager.getVertexConstants();
+ if (memcmp(&vertexConstants, &mAppliedVertexConstants, sizeof(dx_VertexConstants11)) != 0)
{
- mDeviceContext->UpdateSubresource(mDriverConstantBufferVS, 0, NULL, &mVertexConstants, 16, 0);
- memcpy(&mAppliedVertexConstants, &mVertexConstants, sizeof(dx_VertexConstants));
+ ASSERT(mDriverConstantBufferVS != nullptr);
+ if (mDriverConstantBufferVS)
+ {
+ mDeviceContext->UpdateSubresource(mDriverConstantBufferVS, 0, NULL, &vertexConstants,
+ 16, 0);
+ memcpy(&mAppliedVertexConstants, &vertexConstants, sizeof(dx_VertexConstants11));
+ }
}
- if (memcmp(&mPixelConstants, &mAppliedPixelConstants, sizeof(dx_PixelConstants)) != 0)
+ const dx_PixelConstants11 &pixelConstants = mStateManager.getPixelConstants();
+ if (memcmp(&pixelConstants, &mAppliedPixelConstants, sizeof(dx_PixelConstants11)) != 0)
{
- mDeviceContext->UpdateSubresource(mDriverConstantBufferPS, 0, NULL, &mPixelConstants, 16, 0);
- memcpy(&mAppliedPixelConstants, &mPixelConstants, sizeof(dx_PixelConstants));
+ ASSERT(mDriverConstantBufferPS != nullptr);
+ if (mDriverConstantBufferPS)
+ {
+ mDeviceContext->UpdateSubresource(mDriverConstantBufferPS, 0, NULL, &pixelConstants, 16,
+ 0);
+ memcpy(&mAppliedPixelConstants, &pixelConstants, sizeof(dx_PixelConstants11));
+ }
}
// GSSetConstantBuffers triggers device removal on 9_3, so we should only call it if necessary
- if (programD3D->usesGeometryShader())
+ if (programD3D.usesGeometryShader(drawMode))
{
// needed for the point sprite geometry shader
if (mCurrentGeometryConstantBuffer != mDriverConstantBufferPS)
{
- mDeviceContext->GSSetConstantBuffers(0, 1, &mDriverConstantBufferPS);
- mCurrentGeometryConstantBuffer = mDriverConstantBufferPS;
+ ASSERT(mDriverConstantBufferPS != nullptr);
+ if (mDriverConstantBufferPS)
+ {
+ mDeviceContext->GSSetConstantBuffers(0, 1, &mDriverConstantBufferPS);
+ mCurrentGeometryConstantBuffer = mDriverConstantBufferPS;
+ }
}
}
@@ -2107,45 +2317,27 @@ gl::Error Renderer11::applyUniforms(const ProgramImpl &program, const std::vecto
void Renderer11::markAllStateDirty()
{
- for (size_t rtIndex = 0; rtIndex < ArraySize(mAppliedRTVs); rtIndex++)
- {
- mAppliedRTVs[rtIndex] = DirtyPointer;
- }
- mAppliedDSV = DirtyPointer;
- mDepthStencilInitialized = false;
- mRenderTargetDescInitialized = false;
-
- // We reset the current SRV data because it might not be in sync with D3D's state
- // anymore. For example when a currently used SRV is used as an RTV, D3D silently
- // remove it from its state.
- memset(mCurVertexSRVs.data(), 0, sizeof(SRVRecord) * mCurVertexSRVs.size());
- memset(mCurPixelSRVs.data(), 0, sizeof(SRVRecord) * mCurPixelSRVs.size());
+ TRACE_EVENT0("gpu.angle", "Renderer11::markAllStateDirty");
- ASSERT(mForceSetVertexSamplerStates.size() == mCurVertexSRVs.size());
for (size_t vsamplerId = 0; vsamplerId < mForceSetVertexSamplerStates.size(); ++vsamplerId)
{
mForceSetVertexSamplerStates[vsamplerId] = true;
}
- ASSERT(mForceSetPixelSamplerStates.size() == mCurPixelSRVs.size());
for (size_t fsamplerId = 0; fsamplerId < mForceSetPixelSamplerStates.size(); ++fsamplerId)
{
mForceSetPixelSamplerStates[fsamplerId] = true;
}
- mForceSetBlendState = true;
- mForceSetRasterState = true;
- mForceSetDepthStencilState = true;
- mForceSetScissor = true;
- mForceSetViewport = true;
+ mStateManager.invalidateEverything();
mAppliedIB = NULL;
mAppliedIBFormat = DXGI_FORMAT_UNKNOWN;
mAppliedIBOffset = 0;
- mAppliedVertexShader = DirtyPointer;
- mAppliedGeometryShader = DirtyPointer;
- mAppliedPixelShader = DirtyPointer;
+ mAppliedVertexShader = angle::DirtyPointer;
+ mAppliedGeometryShader = angle::DirtyPointer;
+ mAppliedPixelShader = angle::DirtyPointer;
mAppliedNumXFBBindings = static_cast<size_t>(-1);
@@ -2155,8 +2347,8 @@ void Renderer11::markAllStateDirty()
mAppliedTFOffsets[i] = 0;
}
- memset(&mAppliedVertexConstants, 0, sizeof(dx_VertexConstants));
- memset(&mAppliedPixelConstants, 0, sizeof(dx_PixelConstants));
+ memset(&mAppliedVertexConstants, 0, sizeof(dx_VertexConstants11));
+ memset(&mAppliedPixelConstants, 0, sizeof(dx_PixelConstants11));
mInputLayoutCache.markDirty();
@@ -2238,20 +2430,16 @@ bool Renderer11::testDeviceResettable()
D3D_FEATURE_LEVEL dummyFeatureLevel;
ID3D11DeviceContext* dummyContext;
- HRESULT result = D3D11CreateDevice(NULL,
- mDriverType,
- NULL,
+ ASSERT(mRequestedDriverType != D3D_DRIVER_TYPE_UNKNOWN);
+ HRESULT result = D3D11CreateDevice(
+ NULL, mRequestedDriverType, NULL,
#if defined(_DEBUG)
- D3D11_CREATE_DEVICE_DEBUG,
+ D3D11_CREATE_DEVICE_DEBUG,
#else
- 0,
+ 0,
#endif
- mAvailableFeatureLevels.data(),
- mAvailableFeatureLevels.size(),
- D3D11_SDK_VERSION,
- &dummyDevice,
- &dummyFeatureLevel,
- &dummyContext);
+ mAvailableFeatureLevels.data(), static_cast<unsigned int>(mAvailableFeatureLevels.size()),
+ D3D11_SDK_VERSION, &dummyDevice, &dummyFeatureLevel, &dummyContext);
if (!mDevice || FAILED(result))
{
@@ -2270,6 +2458,13 @@ void Renderer11::release()
releaseDeviceResources();
+ if (!mCreatedWithDeviceEXT)
+ {
+ // Only delete the device if the Renderer11 owns it
+ // Otherwise we should keep it around in case we try to reinitialize the renderer later
+ SafeDelete(mEGLDevice);
+ }
+
SafeRelease(mDxgiFactory);
SafeRelease(mDxgiAdapter);
@@ -2285,6 +2480,9 @@ void Renderer11::release()
}
SafeRelease(mDevice);
+#if !defined(ANGLE_MINGW32_COMPAT)
+ SafeRelease(mDebug);
+#endif
if (mD3d11Module)
{
@@ -2298,7 +2496,15 @@ void Renderer11::release()
mDxgiModule = NULL;
}
+ if (mDCompModule)
+ {
+ FreeLibrary(mDCompModule);
+ mDCompModule = NULL;
+ }
+
mCompiler.release();
+
+ mSupportsShareHandles.reset();
}
bool Renderer11::resetDevice()
@@ -2318,11 +2524,6 @@ bool Renderer11::resetDevice()
return true;
}
-VendorID Renderer11::getVendorId() const
-{
- return static_cast<VendorID>(mAdapterDescription.VendorId);
-}
-
std::string Renderer11::getRendererDescription() const
{
std::ostringstream rendererString;
@@ -2336,24 +2537,29 @@ std::string Renderer11::getRendererDescription() const
return rendererString.str();
}
-GUID Renderer11::getAdapterIdentifier() const
+DeviceIdentifier Renderer11::getAdapterIdentifier() const
{
- // Use the adapter LUID as our adapter ID
- // This number is local to a machine is only guaranteed to be unique between restarts
- static_assert(sizeof(LUID) <= sizeof(GUID), "Size of GUID must be at least as large as LUID.");
- GUID adapterId = {0};
- memcpy(&adapterId, &mAdapterDescription.AdapterLuid, sizeof(LUID));
- return adapterId;
+ // Don't use the AdapterLuid here, since that doesn't persist across reboot.
+ DeviceIdentifier deviceIdentifier = { 0 };
+ deviceIdentifier.VendorId = mAdapterDescription.VendorId;
+ deviceIdentifier.DeviceId = mAdapterDescription.DeviceId;
+ deviceIdentifier.SubSysId = mAdapterDescription.SubSysId;
+ deviceIdentifier.Revision = mAdapterDescription.Revision;
+ deviceIdentifier.FeatureLevel = static_cast<UINT>(mRenderer11DeviceCaps.featureLevel);
+
+ return deviceIdentifier;
}
unsigned int Renderer11::getReservedVertexUniformVectors() const
{
- return 0; // Driver uniforms are stored in a separate constant buffer
+ // Driver uniforms are stored in a separate constant buffer
+ return d3d11_gl::GetReservedVertexUniformVectors(mRenderer11DeviceCaps.featureLevel);
}
unsigned int Renderer11::getReservedFragmentUniformVectors() const
{
- return 0; // Driver uniforms are stored in a separate constant buffer
+ // Driver uniforms are stored in a separate constant buffer
+ return d3d11_gl::GetReservedFragmentUniformVectors(mRenderer11DeviceCaps.featureLevel);
}
unsigned int Renderer11::getReservedVertexUniformBuffers() const
@@ -2368,24 +2574,100 @@ unsigned int Renderer11::getReservedFragmentUniformBuffers() const
return 2;
}
+d3d11::ANGLED3D11DeviceType Renderer11::getDeviceType() const
+{
+ if (mCreatedWithDeviceEXT)
+ {
+ return d3d11::GetDeviceType(mDevice);
+ }
+
+ if ((mRequestedDriverType == D3D_DRIVER_TYPE_SOFTWARE) ||
+ (mRequestedDriverType == D3D_DRIVER_TYPE_REFERENCE) ||
+ (mRequestedDriverType == D3D_DRIVER_TYPE_NULL))
+ {
+ return d3d11::ANGLE_D3D11_DEVICE_TYPE_SOFTWARE_REF_OR_NULL;
+ }
+
+ if (mRequestedDriverType == D3D_DRIVER_TYPE_WARP)
+ {
+ return d3d11::ANGLE_D3D11_DEVICE_TYPE_WARP;
+ }
+
+ return d3d11::ANGLE_D3D11_DEVICE_TYPE_HARDWARE;
+}
+
bool Renderer11::getShareHandleSupport() const
{
+ if (mSupportsShareHandles.valid())
+ {
+ return mSupportsShareHandles.value();
+ }
+
// We only currently support share handles with BGRA surfaces, because
// chrome needs BGRA. Once chrome fixes this, we should always support them.
+ if (!getRendererExtensions().textureFormatBGRA8888)
+ {
+ mSupportsShareHandles = false;
+ return false;
+ }
+
// PIX doesn't seem to support using share handles, so disable them.
+ if (gl::DebugAnnotationsActive())
+ {
+ mSupportsShareHandles = false;
+ return false;
+ }
+
// Also disable share handles on Feature Level 9_3, since it doesn't support share handles on RGBA8 textures/swapchains.
- return getRendererExtensions().textureFormatBGRA8888 && !gl::DebugAnnotationsActive();// && !(mFeatureLevel <= D3D_FEATURE_LEVEL_9_3); Qt: we don't care about the 9_3 limitation
-}
+ if (mRenderer11DeviceCaps.featureLevel <= D3D_FEATURE_LEVEL_9_3)
+ {
+ mSupportsShareHandles = false;
+ return false;
+ }
-bool Renderer11::getPostSubBufferSupport() const
-{
- // D3D11 does not support present with dirty rectangles until D3D11.1 and DXGI 1.2.
- return false;
+ // Find out which type of D3D11 device the Renderer11 is using
+ d3d11::ANGLED3D11DeviceType deviceType = getDeviceType();
+ if (deviceType == d3d11::ANGLE_D3D11_DEVICE_TYPE_UNKNOWN)
+ {
+ mSupportsShareHandles = false;
+ return false;
+ }
+
+ if (deviceType == d3d11::ANGLE_D3D11_DEVICE_TYPE_SOFTWARE_REF_OR_NULL)
+ {
+ // Software/Reference/NULL devices don't support share handles
+ mSupportsShareHandles = false;
+ return false;
+ }
+
+ if (deviceType == d3d11::ANGLE_D3D11_DEVICE_TYPE_WARP)
+ {
+#if !defined(ANGLE_ENABLE_WINDOWS_STORE) && !defined(__GNUC__)
+ if (!IsWindows8OrGreater())
+ {
+ // WARP on Windows 7 doesn't support shared handles
+ mSupportsShareHandles = false;
+ return false;
+ }
+#endif // ANGLE_ENABLE_WINDOWS_STORE
+
+ // WARP on Windows 8.0+ supports shared handles when shared with another WARP device
+ // TODO: allow applications to query for HARDWARE or WARP-specific share handles,
+ // to prevent them trying to use a WARP share handle with an a HW device (or
+ // vice-versa)
+ // e.g. by creating EGL_D3D11_[HARDWARE/WARP]_DEVICE_SHARE_HANDLE_ANGLE
+ mSupportsShareHandles = true;
+ return true;
+ }
+
+ ASSERT(mCreatedWithDeviceEXT || mRequestedDriverType == D3D_DRIVER_TYPE_HARDWARE);
+ mSupportsShareHandles = true;
+ return true;
}
int Renderer11::getMajorShaderModel() const
{
- switch (mFeatureLevel)
+ switch (mRenderer11DeviceCaps.featureLevel)
{
case D3D_FEATURE_LEVEL_11_0: return D3D11_SHADER_MAJOR_VERSION; // 5
case D3D_FEATURE_LEVEL_10_1: return D3D10_1_SHADER_MAJOR_VERSION; // 4
@@ -2397,7 +2679,7 @@ int Renderer11::getMajorShaderModel() const
int Renderer11::getMinorShaderModel() const
{
- switch (mFeatureLevel)
+ switch (mRenderer11DeviceCaps.featureLevel)
{
case D3D_FEATURE_LEVEL_11_0: return D3D11_SHADER_MINOR_VERSION; // 0
case D3D_FEATURE_LEVEL_10_1: return D3D10_1_SHADER_MINOR_VERSION; // 1
@@ -2409,7 +2691,7 @@ int Renderer11::getMinorShaderModel() const
std::string Renderer11::getShaderModelSuffix() const
{
- switch (mFeatureLevel)
+ switch (mRenderer11DeviceCaps.featureLevel)
{
case D3D_FEATURE_LEVEL_11_0: return "";
case D3D_FEATURE_LEVEL_10_1: return "";
@@ -2419,14 +2701,25 @@ std::string Renderer11::getShaderModelSuffix() const
}
}
+const WorkaroundsD3D &RendererD3D::getWorkarounds() const
+{
+ if (!mWorkaroundsInitialized)
+ {
+ mWorkarounds = generateWorkarounds();
+ mWorkaroundsInitialized = true;
+ }
+
+ return mWorkarounds;
+}
+
gl::Error Renderer11::copyImage2D(const gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat,
const gl::Offset &destOffset, TextureStorage *storage, GLint level)
{
- gl::FramebufferAttachment *colorbuffer = framebuffer->getReadColorbuffer();
+ const gl::FramebufferAttachment *colorbuffer = framebuffer->getReadColorbuffer();
ASSERT(colorbuffer);
RenderTarget11 *sourceRenderTarget = NULL;
- gl::Error error = d3d11::GetAttachmentRenderTarget(colorbuffer, &sourceRenderTarget);
+ gl::Error error = colorbuffer->getRenderTarget(&sourceRenderTarget);
if (error.isError())
{
return error;
@@ -2436,7 +2729,7 @@ gl::Error Renderer11::copyImage2D(const gl::Framebuffer *framebuffer, const gl::
ID3D11ShaderResourceView *source = sourceRenderTarget->getShaderResourceView();
ASSERT(source);
- TextureStorage11_2D *storage11 = TextureStorage11_2D::makeTextureStorage11_2D(storage);
+ TextureStorage11_2D *storage11 = GetAs<TextureStorage11_2D>(storage);
ASSERT(storage11);
gl::ImageIndex index = gl::ImageIndex::Make2D(level);
@@ -2448,18 +2741,26 @@ gl::Error Renderer11::copyImage2D(const gl::Framebuffer *framebuffer, const gl::
}
ASSERT(destRenderTarget);
- ID3D11RenderTargetView *dest = RenderTarget11::makeRenderTarget11(destRenderTarget)->getRenderTargetView();
+ ID3D11RenderTargetView *dest = GetAs<RenderTarget11>(destRenderTarget)->getRenderTargetView();
ASSERT(dest);
gl::Box sourceArea(sourceRect.x, sourceRect.y, 0, sourceRect.width, sourceRect.height, 1);
gl::Extents sourceSize(sourceRenderTarget->getWidth(), sourceRenderTarget->getHeight(), 1);
+ const bool invertSource = UsePresentPathFast(this, colorbuffer);
+ if (invertSource)
+ {
+ sourceArea.y = sourceSize.height - sourceRect.y;
+ sourceArea.height = -sourceArea.height;
+ }
+
gl::Box destArea(destOffset.x, destOffset.y, 0, sourceRect.width, sourceRect.height, 1);
gl::Extents destSize(destRenderTarget->getWidth(), destRenderTarget->getHeight(), 1);
// Use nearest filtering because source and destination are the same size for the direct
// copy
- mBlit->copyTexture(source, sourceArea, sourceSize, dest, destArea, destSize, NULL, destFormat, GL_NEAREST);
+ error = mBlit->copyTexture(source, sourceArea, sourceSize, dest, destArea, destSize, NULL,
+ destFormat, GL_NEAREST, false);
if (error.isError())
{
return error;
@@ -2473,11 +2774,11 @@ gl::Error Renderer11::copyImage2D(const gl::Framebuffer *framebuffer, const gl::
gl::Error Renderer11::copyImageCube(const gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat,
const gl::Offset &destOffset, TextureStorage *storage, GLenum target, GLint level)
{
- gl::FramebufferAttachment *colorbuffer = framebuffer->getReadColorbuffer();
+ const gl::FramebufferAttachment *colorbuffer = framebuffer->getReadColorbuffer();
ASSERT(colorbuffer);
RenderTarget11 *sourceRenderTarget = NULL;
- gl::Error error = d3d11::GetAttachmentRenderTarget(colorbuffer, &sourceRenderTarget);
+ gl::Error error = colorbuffer->getRenderTarget(&sourceRenderTarget);
if (error.isError())
{
return error;
@@ -2487,7 +2788,7 @@ gl::Error Renderer11::copyImageCube(const gl::Framebuffer *framebuffer, const gl
ID3D11ShaderResourceView *source = sourceRenderTarget->getShaderResourceView();
ASSERT(source);
- TextureStorage11_Cube *storage11 = TextureStorage11_Cube::makeTextureStorage11_Cube(storage);
+ TextureStorage11_Cube *storage11 = GetAs<TextureStorage11_Cube>(storage);
ASSERT(storage11);
gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
@@ -2499,18 +2800,26 @@ gl::Error Renderer11::copyImageCube(const gl::Framebuffer *framebuffer, const gl
}
ASSERT(destRenderTarget);
- ID3D11RenderTargetView *dest = RenderTarget11::makeRenderTarget11(destRenderTarget)->getRenderTargetView();
+ ID3D11RenderTargetView *dest = GetAs<RenderTarget11>(destRenderTarget)->getRenderTargetView();
ASSERT(dest);
gl::Box sourceArea(sourceRect.x, sourceRect.y, 0, sourceRect.width, sourceRect.height, 1);
gl::Extents sourceSize(sourceRenderTarget->getWidth(), sourceRenderTarget->getHeight(), 1);
+ const bool invertSource = UsePresentPathFast(this, colorbuffer);
+ if (invertSource)
+ {
+ sourceArea.y = sourceSize.height - sourceRect.y;
+ sourceArea.height = -sourceArea.height;
+ }
+
gl::Box destArea(destOffset.x, destOffset.y, 0, sourceRect.width, sourceRect.height, 1);
gl::Extents destSize(destRenderTarget->getWidth(), destRenderTarget->getHeight(), 1);
// Use nearest filtering because source and destination are the same size for the direct
// copy
- error = mBlit->copyTexture(source, sourceArea, sourceSize, dest, destArea, destSize, NULL, destFormat, GL_NEAREST);
+ error = mBlit->copyTexture(source, sourceArea, sourceSize, dest, destArea, destSize, NULL,
+ destFormat, GL_NEAREST, false);
if (error.isError())
{
return error;
@@ -2524,11 +2833,11 @@ gl::Error Renderer11::copyImageCube(const gl::Framebuffer *framebuffer, const gl
gl::Error Renderer11::copyImage3D(const gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat,
const gl::Offset &destOffset, TextureStorage *storage, GLint level)
{
- gl::FramebufferAttachment *colorbuffer = framebuffer->getReadColorbuffer();
+ const gl::FramebufferAttachment *colorbuffer = framebuffer->getReadColorbuffer();
ASSERT(colorbuffer);
RenderTarget11 *sourceRenderTarget = NULL;
- gl::Error error = d3d11::GetAttachmentRenderTarget(colorbuffer, &sourceRenderTarget);
+ gl::Error error = colorbuffer->getRenderTarget(&sourceRenderTarget);
if (error.isError())
{
return error;
@@ -2538,7 +2847,7 @@ gl::Error Renderer11::copyImage3D(const gl::Framebuffer *framebuffer, const gl::
ID3D11ShaderResourceView *source = sourceRenderTarget->getShaderResourceView();
ASSERT(source);
- TextureStorage11_3D *storage11 = TextureStorage11_3D::makeTextureStorage11_3D(storage);
+ TextureStorage11_3D *storage11 = GetAs<TextureStorage11_3D>(storage);
ASSERT(storage11);
gl::ImageIndex index = gl::ImageIndex::Make3D(level, destOffset.z);
@@ -2550,7 +2859,7 @@ gl::Error Renderer11::copyImage3D(const gl::Framebuffer *framebuffer, const gl::
}
ASSERT(destRenderTarget);
- ID3D11RenderTargetView *dest = RenderTarget11::makeRenderTarget11(destRenderTarget)->getRenderTargetView();
+ ID3D11RenderTargetView *dest = GetAs<RenderTarget11>(destRenderTarget)->getRenderTargetView();
ASSERT(dest);
gl::Box sourceArea(sourceRect.x, sourceRect.y, 0, sourceRect.width, sourceRect.height, 1);
@@ -2561,7 +2870,8 @@ gl::Error Renderer11::copyImage3D(const gl::Framebuffer *framebuffer, const gl::
// Use nearest filtering because source and destination are the same size for the direct
// copy
- error = mBlit->copyTexture(source, sourceArea, sourceSize, dest, destArea, destSize, NULL, destFormat, GL_NEAREST);
+ error = mBlit->copyTexture(source, sourceArea, sourceSize, dest, destArea, destSize, NULL,
+ destFormat, GL_NEAREST, false);
if (error.isError())
{
return error;
@@ -2575,11 +2885,11 @@ gl::Error Renderer11::copyImage3D(const gl::Framebuffer *framebuffer, const gl::
gl::Error Renderer11::copyImage2DArray(const gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat,
const gl::Offset &destOffset, TextureStorage *storage, GLint level)
{
- gl::FramebufferAttachment *colorbuffer = framebuffer->getReadColorbuffer();
+ const gl::FramebufferAttachment *colorbuffer = framebuffer->getReadColorbuffer();
ASSERT(colorbuffer);
RenderTarget11 *sourceRenderTarget = NULL;
- gl::Error error = d3d11::GetAttachmentRenderTarget(colorbuffer, &sourceRenderTarget);
+ gl::Error error = colorbuffer->getRenderTarget(&sourceRenderTarget);
if (error.isError())
{
return error;
@@ -2589,7 +2899,7 @@ gl::Error Renderer11::copyImage2DArray(const gl::Framebuffer *framebuffer, const
ID3D11ShaderResourceView *source = sourceRenderTarget->getShaderResourceView();
ASSERT(source);
- TextureStorage11_2DArray *storage11 = TextureStorage11_2DArray::makeTextureStorage11_2DArray(storage);
+ TextureStorage11_2DArray *storage11 = GetAs<TextureStorage11_2DArray>(storage);
ASSERT(storage11);
gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, destOffset.z);
@@ -2601,7 +2911,7 @@ gl::Error Renderer11::copyImage2DArray(const gl::Framebuffer *framebuffer, const
}
ASSERT(destRenderTarget);
- ID3D11RenderTargetView *dest = RenderTarget11::makeRenderTarget11(destRenderTarget)->getRenderTargetView();
+ ID3D11RenderTargetView *dest = GetAs<RenderTarget11>(destRenderTarget)->getRenderTargetView();
ASSERT(dest);
gl::Box sourceArea(sourceRect.x, sourceRect.y, 0, sourceRect.width, sourceRect.height, 1);
@@ -2612,7 +2922,8 @@ gl::Error Renderer11::copyImage2DArray(const gl::Framebuffer *framebuffer, const
// Use nearest filtering because source and destination are the same size for the direct
// copy
- error = mBlit->copyTexture(source, sourceArea, sourceSize, dest, destArea, destSize, NULL, destFormat, GL_NEAREST);
+ error = mBlit->copyTexture(source, sourceArea, sourceSize, dest, destArea, destSize, NULL,
+ destFormat, GL_NEAREST, false);
if (error.isError())
{
return error;
@@ -2640,14 +2951,14 @@ void Renderer11::setOneTimeRenderTarget(ID3D11RenderTargetView *renderTargetView
// Do not preserve the serial for this one-time-use render target
for (size_t rtIndex = 0; rtIndex < ArraySize(mAppliedRTVs); rtIndex++)
{
- mAppliedRTVs[rtIndex] = DirtyPointer;
+ mAppliedRTVs[rtIndex] = angle::DirtyPointer;
}
- mAppliedDSV = DirtyPointer;
+ mAppliedDSV = angle::DirtyPointer;
}
gl::Error Renderer11::createRenderTarget(int width, int height, GLenum format, GLsizei samples, RenderTargetD3D **outRT)
{
- const d3d11::TextureFormat &formatInfo = d3d11::GetTextureFormatInfo(format, mFeatureLevel);
+ const d3d11::TextureFormat &formatInfo = d3d11::GetTextureFormatInfo(format, mRenderer11DeviceCaps);
const gl::TextureCaps &textureCaps = getRendererTextureCaps().get(format);
GLuint supportedSamples = textureCaps.getNearestSamples(samples);
@@ -2779,9 +3090,26 @@ gl::Error Renderer11::createRenderTarget(int width, int height, GLenum format, G
return gl::Error(GL_NO_ERROR);
}
-FramebufferImpl *Renderer11::createDefaultFramebuffer(const gl::Framebuffer::Data &data)
+gl::Error Renderer11::createRenderTargetCopy(RenderTargetD3D *source, RenderTargetD3D **outRT)
{
- return createFramebuffer(data);
+ ASSERT(source != nullptr);
+
+ RenderTargetD3D *newRT = nullptr;
+ gl::Error error = createRenderTarget(source->getWidth(), source->getHeight(),
+ source->getInternalFormat(), source->getSamples(), &newRT);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ RenderTarget11 *source11 = GetAs<RenderTarget11>(source);
+ RenderTarget11 *dest11 = GetAs<RenderTarget11>(newRT);
+
+ mDeviceContext->CopySubresourceRegion(dest11->getTexture(), dest11->getSubresourceIndex(), 0, 0,
+ 0, source11->getTexture(),
+ source11->getSubresourceIndex(), nullptr);
+ *outRT = newRT;
+ return gl::Error(GL_NO_ERROR);
}
FramebufferImpl *Renderer11::createFramebuffer(const gl::Framebuffer::Data &data)
@@ -2789,24 +3117,22 @@ FramebufferImpl *Renderer11::createFramebuffer(const gl::Framebuffer::Data &data
return new Framebuffer11(data, this);
}
-CompilerImpl *Renderer11::createCompiler(const gl::Data &data)
+ShaderImpl *Renderer11::createShader(const gl::Shader::Data &data)
{
- return new CompilerD3D(data, SH_HLSL11_OUTPUT);
+ return new ShaderD3D(data);
}
-ShaderImpl *Renderer11::createShader(GLenum type)
+ProgramImpl *Renderer11::createProgram(const gl::Program::Data &data)
{
- return new ShaderD3D(type);
+ return new ProgramD3D(data, this);
}
-ProgramImpl *Renderer11::createProgram()
-{
- return new ProgramD3D(this);
-}
-
-gl::Error Renderer11::loadExecutable(const void *function, size_t length, ShaderType type,
- const std::vector<gl::LinkedVarying> &transformFeedbackVaryings,
- bool separatedOutputBuffers, ShaderExecutableD3D **outExecutable)
+gl::Error Renderer11::loadExecutable(const void *function,
+ size_t length,
+ ShaderType type,
+ const std::vector<D3DVarying> &streamOutVaryings,
+ bool separatedOutputBuffers,
+ ShaderExecutableD3D **outExecutable)
{
switch (type)
{
@@ -2822,29 +3148,28 @@ gl::Error Renderer11::loadExecutable(const void *function, size_t length, Shader
return gl::Error(GL_OUT_OF_MEMORY, "Failed to create vertex shader, result: 0x%X.", result);
}
- if (transformFeedbackVaryings.size() > 0)
+ if (!streamOutVaryings.empty())
{
std::vector<D3D11_SO_DECLARATION_ENTRY> soDeclaration;
- for (size_t i = 0; i < transformFeedbackVaryings.size(); i++)
+ soDeclaration.reserve(streamOutVaryings.size());
+
+ for (const auto &streamOutVarying : streamOutVaryings)
{
- const gl::LinkedVarying &varying = transformFeedbackVaryings[i];
- GLenum transposedType = gl::TransposeMatrixType(varying.type);
-
- for (size_t j = 0; j < varying.semanticIndexCount; j++)
- {
- D3D11_SO_DECLARATION_ENTRY entry = { 0 };
- entry.Stream = 0;
- entry.SemanticName = varying.semanticName.c_str();
- entry.SemanticIndex = varying.semanticIndex + j;
- entry.StartComponent = 0;
- entry.ComponentCount = gl::VariableColumnCount(transposedType);
- entry.OutputSlot = (separatedOutputBuffers ? i : 0);
- soDeclaration.push_back(entry);
- }
+ D3D11_SO_DECLARATION_ENTRY entry = {0};
+ entry.Stream = 0;
+ entry.SemanticName = streamOutVarying.semanticName.c_str();
+ entry.SemanticIndex = streamOutVarying.semanticIndex;
+ entry.StartComponent = 0;
+ entry.ComponentCount = static_cast<BYTE>(streamOutVarying.componentCount);
+ entry.OutputSlot = static_cast<BYTE>(
+ (separatedOutputBuffers ? streamOutVarying.outputSlot : 0));
+ soDeclaration.push_back(entry);
}
- result = mDevice->CreateGeometryShaderWithStreamOutput(function, length, soDeclaration.data(), soDeclaration.size(),
- NULL, 0, 0, NULL, &streamOutShader);
+ result = mDevice->CreateGeometryShaderWithStreamOutput(
+ function, static_cast<unsigned int>(length), soDeclaration.data(),
+ static_cast<unsigned int>(soDeclaration.size()), NULL, 0, 0, NULL,
+ &streamOutShader);
ASSERT(SUCCEEDED(result));
if (FAILED(result))
{
@@ -2891,9 +3216,12 @@ gl::Error Renderer11::loadExecutable(const void *function, size_t length, Shader
return gl::Error(GL_NO_ERROR);
}
-gl::Error Renderer11::compileToExecutable(gl::InfoLog &infoLog, const std::string &shaderHLSL, ShaderType type,
- const std::vector<gl::LinkedVarying> &transformFeedbackVaryings,
- bool separatedOutputBuffers, const D3DCompilerWorkarounds &workarounds,
+gl::Error Renderer11::compileToExecutable(gl::InfoLog &infoLog,
+ const std::string &shaderHLSL,
+ ShaderType type,
+ const std::vector<D3DVarying> &streamOutVaryings,
+ bool separatedOutputBuffers,
+ const D3DCompilerWorkarounds &workarounds,
ShaderExecutableD3D **outExectuable)
{
const char *profileType = NULL;
@@ -2936,6 +3264,15 @@ gl::Error Renderer11::compileToExecutable(gl::InfoLog &infoLog, const std::strin
configs.push_back(CompileConfig(flags | D3DCOMPILE_SKIP_VALIDATION, "skip validation" ));
configs.push_back(CompileConfig(flags | D3DCOMPILE_SKIP_OPTIMIZATION, "skip optimization"));
+ if (getMajorShaderModel() == 4 && getShaderModelSuffix() != "")
+ {
+ // Some shaders might cause a "blob content mismatch between level9 and d3d10 shader".
+ // e.g. dEQP-GLES2.functional.shaders.struct.local.loop_nested_struct_array_*.
+ // Using the [unroll] directive works around this, as does this D3DCompile flag.
+ configs.push_back(
+ CompileConfig(flags | D3DCOMPILE_AVOID_FLOW_CONTROL, "avoid flow control"));
+ }
+
D3D_SHADER_MACRO loopMacros[] = { {"ANGLE_ENABLE_LOOP_FLATTEN", "1"}, {0, 0} };
ID3DBlob *binary = NULL;
@@ -2955,7 +3292,7 @@ gl::Error Renderer11::compileToExecutable(gl::InfoLog &infoLog, const std::strin
}
error = loadExecutable(binary->GetBufferPointer(), binary->GetBufferSize(), type,
- transformFeedbackVaryings, separatedOutputBuffers, outExectuable);
+ streamOutVaryings, separatedOutputBuffers, outExectuable);
SafeRelease(binary);
if (error.isError())
@@ -2988,12 +3325,14 @@ IndexBuffer *Renderer11::createIndexBuffer()
BufferImpl *Renderer11::createBuffer()
{
- return new Buffer11(this);
+ Buffer11 *buffer = new Buffer11(this);
+ mAliveBuffers.insert(buffer);
+ return buffer;
}
-VertexArrayImpl *Renderer11::createVertexArray()
+VertexArrayImpl *Renderer11::createVertexArray(const gl::VertexArray::Data &data)
{
- return new VertexArray11(this);
+ return new VertexArray11(data);
}
QueryImpl *Renderer11::createQuery(GLenum type)
@@ -3021,7 +3360,7 @@ bool Renderer11::supportsFastCopyBufferToTexture(GLenum internalFormat) const
ASSERT(getRendererExtensions().pixelBufferObject);
const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat);
- const d3d11::TextureFormat &d3d11FormatInfo = d3d11::GetTextureFormatInfo(internalFormat, mFeatureLevel);
+ const d3d11::TextureFormat &d3d11FormatInfo = d3d11::GetTextureFormatInfo(internalFormat, mRenderer11DeviceCaps);
const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(d3d11FormatInfo.texFormat);
// sRGB formats do not work with D3D11 buffer SRVs
@@ -3065,17 +3404,42 @@ ImageD3D *Renderer11::createImage()
gl::Error Renderer11::generateMipmap(ImageD3D *dest, ImageD3D *src)
{
- Image11 *dest11 = Image11::makeImage11(dest);
- Image11 *src11 = Image11::makeImage11(src);
+ Image11 *dest11 = GetAs<Image11>(dest);
+ Image11 *src11 = GetAs<Image11>(src);
return Image11::generateMipmap(dest11, src11);
}
+gl::Error Renderer11::generateMipmapsUsingD3D(TextureStorage *storage,
+ const gl::TextureState &textureState)
+{
+ TextureStorage11 *storage11 = GetAs<TextureStorage11>(storage);
+
+ ASSERT(storage11->isRenderTarget());
+ ASSERT(storage11->supportsNativeMipmapFunction());
+
+ ID3D11ShaderResourceView *srv;
+ gl::Error error = storage11->getSRVLevels(textureState.baseLevel, textureState.maxLevel, &srv);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ mDeviceContext->GenerateMips(srv);
+
+ return gl::Error(GL_NO_ERROR);
+}
+
TextureStorage *Renderer11::createTextureStorage2D(SwapChainD3D *swapChain)
{
- SwapChain11 *swapChain11 = SwapChain11::makeSwapChain11(swapChain);
+ SwapChain11 *swapChain11 = GetAs<SwapChain11>(swapChain);
return new TextureStorage11_2D(this, swapChain11);
}
+TextureStorage *Renderer11::createTextureStorageEGLImage(EGLImageD3D *eglImage)
+{
+ return new TextureStorage11_EGLImage(this, eglImage);
+}
+
TextureStorage *Renderer11::createTextureStorage2D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels, bool hintLevelZeroOnly)
{
return new TextureStorage11_2D(this, internalformat, renderTarget, width, height, levels, hintLevelZeroOnly);
@@ -3117,28 +3481,53 @@ RenderbufferImpl *Renderer11::createRenderbuffer()
return renderbuffer;
}
-gl::Error Renderer11::readTextureData(ID3D11Texture2D *texture, unsigned int subResource, const gl::Rectangle &area, GLenum format,
- GLenum type, GLuint outputPitch, const gl::PixelPackState &pack, uint8_t *pixels)
+gl::Error Renderer11::readFromAttachment(const gl::FramebufferAttachment &srcAttachment,
+ const gl::Rectangle &sourceArea,
+ GLenum format,
+ GLenum type,
+ GLuint outputPitch,
+ const gl::PixelPackState &pack,
+ uint8_t *pixelsOut)
{
- ASSERT(area.width >= 0);
- ASSERT(area.height >= 0);
+ ASSERT(sourceArea.width >= 0);
+ ASSERT(sourceArea.height >= 0);
- D3D11_TEXTURE2D_DESC textureDesc;
- texture->GetDesc(&textureDesc);
+ const bool invertTexture = UsePresentPathFast(this, &srcAttachment);
+
+ RenderTargetD3D *renderTarget = nullptr;
+ gl::Error error = srcAttachment.getRenderTarget(&renderTarget);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ RenderTarget11 *rt11 = GetAs<RenderTarget11>(renderTarget);
+ ASSERT(rt11->getTexture());
+
+ TextureHelper11 textureHelper = TextureHelper11::MakeAndReference(rt11->getTexture());
+ unsigned int sourceSubResource = rt11->getSubresourceIndex();
+
+ const gl::Extents &texSize = textureHelper.getExtents();
+
+ gl::Rectangle actualArea = sourceArea;
+ if (invertTexture)
+ {
+ actualArea.y = texSize.height - actualArea.y - actualArea.height;
+ }
// Clamp read region to the defined texture boundaries, preventing out of bounds reads
// and reads of uninitialized data.
gl::Rectangle safeArea;
- safeArea.x = gl::clamp(area.x, 0, static_cast<int>(textureDesc.Width));
- safeArea.y = gl::clamp(area.y, 0, static_cast<int>(textureDesc.Height));
- safeArea.width = gl::clamp(area.width + std::min(area.x, 0), 0,
- static_cast<int>(textureDesc.Width) - safeArea.x);
- safeArea.height = gl::clamp(area.height + std::min(area.y, 0), 0,
- static_cast<int>(textureDesc.Height) - safeArea.y);
+ safeArea.x = gl::clamp(actualArea.x, 0, texSize.width);
+ safeArea.y = gl::clamp(actualArea.y, 0, texSize.height);
+ safeArea.width =
+ gl::clamp(actualArea.width + std::min(actualArea.x, 0), 0, texSize.width - safeArea.x);
+ safeArea.height =
+ gl::clamp(actualArea.height + std::min(actualArea.y, 0), 0, texSize.height - safeArea.y);
ASSERT(safeArea.x >= 0 && safeArea.y >= 0);
- ASSERT(safeArea.x + safeArea.width <= static_cast<int>(textureDesc.Width));
- ASSERT(safeArea.y + safeArea.height <= static_cast<int>(textureDesc.Height));
+ ASSERT(safeArea.x + safeArea.width <= texSize.width);
+ ASSERT(safeArea.y + safeArea.height <= texSize.height);
if (safeArea.width == 0 || safeArea.height == 0)
{
@@ -3146,35 +3535,29 @@ gl::Error Renderer11::readTextureData(ID3D11Texture2D *texture, unsigned int sub
return gl::Error(GL_NO_ERROR);
}
- D3D11_TEXTURE2D_DESC stagingDesc;
- stagingDesc.Width = safeArea.width;
- stagingDesc.Height = safeArea.height;
- stagingDesc.MipLevels = 1;
- stagingDesc.ArraySize = 1;
- stagingDesc.Format = textureDesc.Format;
- stagingDesc.SampleDesc.Count = 1;
- stagingDesc.SampleDesc.Quality = 0;
- stagingDesc.Usage = D3D11_USAGE_STAGING;
- stagingDesc.BindFlags = 0;
- stagingDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
- stagingDesc.MiscFlags = 0;
-
- ID3D11Texture2D* stagingTex = NULL;
- HRESULT result = mDevice->CreateTexture2D(&stagingDesc, NULL, &stagingTex);
- if (FAILED(result))
+ gl::Extents safeSize(safeArea.width, safeArea.height, 1);
+ auto errorOrResult = CreateStagingTexture(textureHelper.getTextureType(),
+ textureHelper.getFormat(), safeSize, mDevice);
+ if (errorOrResult.isError())
{
- return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal staging texture for ReadPixels, HRESULT: 0x%X.", result);
+ return errorOrResult.getError();
}
- ID3D11Texture2D* srcTex = NULL;
- if (textureDesc.SampleDesc.Count > 1)
+ TextureHelper11 stagingHelper(errorOrResult.getResult());
+ TextureHelper11 resolvedTextureHelper;
+
+ // "srcTexture" usually points to the source texture.
+ // For 2D multisampled textures, it points to the multisampled resolve texture.
+ const TextureHelper11 *srcTexture = &textureHelper;
+
+ if (textureHelper.getTextureType() == GL_TEXTURE_2D && textureHelper.getSampleCount() > 1)
{
D3D11_TEXTURE2D_DESC resolveDesc;
- resolveDesc.Width = textureDesc.Width;
- resolveDesc.Height = textureDesc.Height;
+ resolveDesc.Width = static_cast<UINT>(texSize.width);
+ resolveDesc.Height = static_cast<UINT>(texSize.height);
resolveDesc.MipLevels = 1;
resolveDesc.ArraySize = 1;
- resolveDesc.Format = textureDesc.Format;
+ resolveDesc.Format = textureHelper.getFormat();
resolveDesc.SampleDesc.Count = 1;
resolveDesc.SampleDesc.Quality = 0;
resolveDesc.Usage = D3D11_USAGE_DEFAULT;
@@ -3182,20 +3565,22 @@ gl::Error Renderer11::readTextureData(ID3D11Texture2D *texture, unsigned int sub
resolveDesc.CPUAccessFlags = 0;
resolveDesc.MiscFlags = 0;
- result = mDevice->CreateTexture2D(&resolveDesc, NULL, &srcTex);
+ ID3D11Texture2D *resolveTex2D = nullptr;
+ HRESULT result = mDevice->CreateTexture2D(&resolveDesc, nullptr, &resolveTex2D);
if (FAILED(result))
{
- SafeRelease(stagingTex);
- return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal resolve texture for ReadPixels, HRESULT: 0x%X.", result);
+ return gl::Error(GL_OUT_OF_MEMORY,
+ "Renderer11::readTextureData failed to create internal resolve "
+ "texture for ReadPixels, HRESULT: 0x%X.",
+ result);
}
- mDeviceContext->ResolveSubresource(srcTex, 0, texture, subResource, textureDesc.Format);
- subResource = 0;
- }
- else
- {
- srcTex = texture;
- srcTex->AddRef();
+ mDeviceContext->ResolveSubresource(resolveTex2D, 0, textureHelper.getTexture2D(),
+ sourceSubResource, textureHelper.getFormat());
+ resolvedTextureHelper = TextureHelper11::MakeAndReference(resolveTex2D);
+
+ sourceSubResource = 0;
+ srcTexture = &resolvedTextureHelper;
}
D3D11_BOX srcBox;
@@ -3203,28 +3588,52 @@ gl::Error Renderer11::readTextureData(ID3D11Texture2D *texture, unsigned int sub
srcBox.right = static_cast<UINT>(safeArea.x + safeArea.width);
srcBox.top = static_cast<UINT>(safeArea.y);
srcBox.bottom = static_cast<UINT>(safeArea.y + safeArea.height);
- srcBox.front = 0;
- srcBox.back = 1;
- mDeviceContext->CopySubresourceRegion(stagingTex, 0, 0, 0, 0, srcTex, subResource, &srcBox);
+ // Select the correct layer from a 3D attachment
+ srcBox.front = 0;
+ if (textureHelper.getTextureType() == GL_TEXTURE_3D)
+ {
+ srcBox.front = static_cast<UINT>(srcAttachment.layer());
+ }
+ srcBox.back = srcBox.front + 1;
- SafeRelease(srcTex);
+ mDeviceContext->CopySubresourceRegion(stagingHelper.getResource(), 0, 0, 0, 0,
+ srcTexture->getResource(), sourceSubResource, &srcBox);
- PackPixelsParams packParams(safeArea, format, type, outputPitch, pack, 0);
- gl::Error error = packPixels(stagingTex, packParams, pixels);
+ if (invertTexture)
+ {
+ gl::PixelPackState invertTexturePack;
- SafeRelease(stagingTex);
+ // Create a new PixelPackState with reversed row order. Note that we can't just assign
+ // 'invertTexturePack' to be 'pack' (or memcpy) since that breaks the ref counting/object
+ // tracking in the 'pixelBuffer' members, causing leaks. Instead we must use
+ // pixelBuffer.set() twice, which performs the addRef/release correctly
+ invertTexturePack.alignment = pack.alignment;
+ invertTexturePack.pixelBuffer.set(pack.pixelBuffer.get());
+ invertTexturePack.reverseRowOrder = !pack.reverseRowOrder;
- return error;
+ PackPixelsParams packParams(safeArea, format, type, outputPitch, invertTexturePack, 0);
+ error = packPixels(stagingHelper, packParams, pixelsOut);
+
+ invertTexturePack.pixelBuffer.set(nullptr);
+
+ return error;
+ }
+ else
+ {
+ PackPixelsParams packParams(safeArea, format, type, outputPitch, pack, 0);
+ return packPixels(stagingHelper, packParams, pixelsOut);
+ }
}
-gl::Error Renderer11::packPixels(ID3D11Texture2D *readTexture, const PackPixelsParams &params, uint8_t *pixelsOut)
+gl::Error Renderer11::packPixels(const TextureHelper11 &textureHelper,
+ const PackPixelsParams &params,
+ uint8_t *pixelsOut)
{
- D3D11_TEXTURE2D_DESC textureDesc;
- readTexture->GetDesc(&textureDesc);
+ ID3D11Resource *readResource = textureHelper.getResource();
D3D11_MAPPED_SUBRESOURCE mapping;
- HRESULT hr = mDeviceContext->Map(readTexture, 0, D3D11_MAP_READ, 0, &mapping);
+ HRESULT hr = mDeviceContext->Map(readResource, 0, D3D11_MAP_READ, 0, &mapping);
if (FAILED(hr))
{
ASSERT(hr == E_OUTOFMEMORY);
@@ -3244,7 +3653,7 @@ gl::Error Renderer11::packPixels(ID3D11Texture2D *readTexture, const PackPixelsP
inputPitch = static_cast<int>(mapping.RowPitch);
}
- const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(textureDesc.Format);
+ const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(textureHelper.getFormat());
const gl::InternalFormat &sourceFormatInfo = gl::GetInternalFormatInfo(dxgiFormatInfo.internalFormat);
if (sourceFormatInfo.format == params.format && sourceFormatInfo.type == params.type)
{
@@ -3256,9 +3665,8 @@ gl::Error Renderer11::packPixels(ID3D11Texture2D *readTexture, const PackPixelsP
}
else
{
- const d3d11::DXGIFormat &sourceDXGIFormatInfo = d3d11::GetDXGIFormatInfo(textureDesc.Format);
- ColorCopyFunction fastCopyFunc = sourceDXGIFormatInfo.getFastCopyFunction(params.format, params.type);
-
+ ColorCopyFunction fastCopyFunc =
+ dxgiFormatInfo.getFastCopyFunction(params.format, params.type);
GLenum sizedDestInternalFormat = gl::GetSizedInternalFormat(params.format, params.type);
const gl::InternalFormat &destFormatInfo = gl::GetInternalFormatInfo(sizedDestInternalFormat);
@@ -3278,7 +3686,7 @@ gl::Error Renderer11::packPixels(ID3D11Texture2D *readTexture, const PackPixelsP
}
else
{
- ColorReadFunction colorReadFunction = sourceDXGIFormatInfo.colorReadFunction;
+ ColorReadFunction colorReadFunction = dxgiFormatInfo.colorReadFunction;
ColorWriteFunction colorWriteFunction = GetColorWriteFunction(params.format, params.type);
uint8_t temp[16]; // Maximum size of any Color<T> type used.
@@ -3303,21 +3711,27 @@ gl::Error Renderer11::packPixels(ID3D11Texture2D *readTexture, const PackPixelsP
}
}
- mDeviceContext->Unmap(readTexture, 0);
+ mDeviceContext->Unmap(readResource, 0);
return gl::Error(GL_NO_ERROR);
}
-gl::Error Renderer11::blitRenderbufferRect(const gl::Rectangle &readRect, const gl::Rectangle &drawRect, RenderTargetD3D *readRenderTarget,
- RenderTargetD3D *drawRenderTarget, GLenum filter, const gl::Rectangle *scissor,
- bool colorBlit, bool depthBlit, bool stencilBlit)
+gl::Error Renderer11::blitRenderbufferRect(const gl::Rectangle &readRectIn,
+ const gl::Rectangle &drawRectIn,
+ RenderTargetD3D *readRenderTarget,
+ RenderTargetD3D *drawRenderTarget,
+ GLenum filter,
+ const gl::Rectangle *scissor,
+ bool colorBlit,
+ bool depthBlit,
+ bool stencilBlit)
{
// Since blitRenderbufferRect is called for each render buffer that needs to be blitted,
// it should never be the case that both color and depth/stencil need to be blitted at
// at the same time.
ASSERT(colorBlit != (depthBlit || stencilBlit));
- RenderTarget11 *drawRenderTarget11 = RenderTarget11::makeRenderTarget11(drawRenderTarget);
+ RenderTarget11 *drawRenderTarget11 = GetAs<RenderTarget11>(drawRenderTarget);
if (!drawRenderTarget)
{
return gl::Error(GL_OUT_OF_MEMORY, "Failed to retrieve the internal draw render target from the draw framebuffer.");
@@ -3328,7 +3742,7 @@ gl::Error Renderer11::blitRenderbufferRect(const gl::Rectangle &readRect, const
ID3D11RenderTargetView *drawRTV = drawRenderTarget11->getRenderTargetView();
ID3D11DepthStencilView *drawDSV = drawRenderTarget11->getDepthStencilView();
- RenderTarget11 *readRenderTarget11 = RenderTarget11::makeRenderTarget11(readRenderTarget);
+ RenderTarget11 *readRenderTarget11 = GetAs<RenderTarget11>(readRenderTarget);
if (!readRenderTarget)
{
return gl::Error(GL_OUT_OF_MEMORY, "Failed to retrieve the internal read render target from the read framebuffer.");
@@ -3376,13 +3790,94 @@ gl::Error Renderer11::blitRenderbufferRect(const gl::Rectangle &readRect, const
gl::Extents readSize(readRenderTarget->getWidth(), readRenderTarget->getHeight(), 1);
gl::Extents drawSize(drawRenderTarget->getWidth(), drawRenderTarget->getHeight(), 1);
+ // From the spec:
+ // "The actual region taken from the read framebuffer is limited to the intersection of the
+ // source buffers being transferred, which may include the color buffer selected by the read
+ // buffer, the depth buffer, and / or the stencil buffer depending on mask."
+ // This means negative x and y are out of bounds, and not to be read from. We handle this here
+ // by internally scaling the read and draw rectangles.
+ gl::Rectangle readRect = readRectIn;
+ gl::Rectangle drawRect = drawRectIn;
+ auto readToDrawX = [&drawRectIn, &readRectIn](int readOffset)
+ {
+ double readToDrawScale =
+ static_cast<double>(drawRectIn.width) / static_cast<double>(readRectIn.width);
+ return static_cast<int>(round(static_cast<double>(readOffset) * readToDrawScale));
+ };
+ if (readRect.x < 0)
+ {
+ int readOffset = -readRect.x;
+ readRect.x += readOffset;
+ readRect.width -= readOffset;
+
+ int drawOffset = readToDrawX(readOffset);
+ drawRect.x += drawOffset;
+ drawRect.width -= drawOffset;
+ }
+
+ auto readToDrawY = [&drawRectIn, &readRectIn](int readOffset)
+ {
+ double readToDrawScale =
+ static_cast<double>(drawRectIn.height) / static_cast<double>(readRectIn.height);
+ return static_cast<int>(round(static_cast<double>(readOffset) * readToDrawScale));
+ };
+ if (readRect.y < 0)
+ {
+ int readOffset = -readRect.y;
+ readRect.y += readOffset;
+ readRect.height -= readOffset;
+
+ int drawOffset = readToDrawY(readOffset);
+ drawRect.y += drawOffset;
+ drawRect.height -= drawOffset;
+ }
+
+ if (readRect.x1() < 0)
+ {
+ int readOffset = -readRect.x1();
+ readRect.width += readOffset;
+
+ int drawOffset = readToDrawX(readOffset);
+ drawRect.width += drawOffset;
+ }
+
+ if (readRect.y1() < 0)
+ {
+ int readOffset = -readRect.y1();
+ readRect.height += readOffset;
+
+ int drawOffset = readToDrawY(readOffset);
+ drawRect.height += drawOffset;
+ }
+
bool scissorNeeded = scissor && gl::ClipRectangle(drawRect, *scissor, NULL);
- bool wholeBufferCopy = !scissorNeeded &&
- readRect.x == 0 && readRect.width == readSize.width &&
- readRect.y == 0 && readRect.height == readSize.height &&
- drawRect.x == 0 && drawRect.width == drawSize.width &&
- drawRect.y == 0 && drawRect.height == drawSize.height;
+ const auto &destFormatInfo = gl::GetInternalFormatInfo(drawRenderTarget->getInternalFormat());
+ const auto &srcFormatInfo = gl::GetInternalFormatInfo(readRenderTarget->getInternalFormat());
+ const auto &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(drawRenderTarget11->getDXGIFormat());
+
+ // Some blits require masking off emulated texture channels. eg: from RGBA8 to RGB8, we
+ // emulate RGB8 with RGBA8, so we need to mask off the alpha channel when we copy.
+
+ gl::Color<bool> colorMask;
+ colorMask.red = (srcFormatInfo.redBits > 0) && (destFormatInfo.redBits == 0) &&
+ (dxgiFormatInfo.redBits > 0);
+ colorMask.green = (srcFormatInfo.greenBits > 0) && (destFormatInfo.greenBits == 0) &&
+ (dxgiFormatInfo.greenBits > 0);
+ colorMask.blue = (srcFormatInfo.blueBits > 0) && (destFormatInfo.blueBits == 0) &&
+ (dxgiFormatInfo.blueBits > 0);
+ colorMask.alpha = (srcFormatInfo.alphaBits > 0) && (destFormatInfo.alphaBits == 0) &&
+ (dxgiFormatInfo.alphaBits > 0);
+
+ // We only currently support masking off the alpha channel.
+ bool colorMaskingNeeded = colorMask.alpha;
+ ASSERT(!colorMask.red && !colorMask.green && !colorMask.blue);
+
+ bool wholeBufferCopy = !scissorNeeded && !colorMaskingNeeded && readRect.x == 0 &&
+ readRect.width == readSize.width && readRect.y == 0 &&
+ readRect.height == readSize.height && drawRect.x == 0 &&
+ drawRect.width == drawSize.width && drawRect.y == 0 &&
+ drawRect.height == drawSize.height;
bool stretchRequired = readRect.width != drawRect.width || readRect.height != drawRect.height;
@@ -3393,14 +3888,13 @@ gl::Error Renderer11::blitRenderbufferRect(const gl::Rectangle &readRect, const
drawRect.x < 0 || drawRect.x + drawRect.width > drawSize.width ||
drawRect.y < 0 || drawRect.y + drawRect.height > drawSize.height;
- const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(drawRenderTarget11->getDXGIFormat());
bool partialDSBlit = (dxgiFormatInfo.depthBits > 0 && depthBlit) != (dxgiFormatInfo.stencilBits > 0 && stencilBlit);
gl::Error result(GL_NO_ERROR);
if (readRenderTarget11->getDXGIFormat() == drawRenderTarget11->getDXGIFormat() &&
!stretchRequired && !outOfBounds && !flipRequired && !partialDSBlit &&
- (!(depthBlit || stencilBlit) || wholeBufferCopy))
+ !colorMaskingNeeded && (!(depthBlit || stencilBlit) || wholeBufferCopy))
{
UINT dstX = drawRect.x;
UINT dstY = drawRect.y;
@@ -3470,9 +3964,10 @@ gl::Error Renderer11::blitRenderbufferRect(const gl::Rectangle &readRect, const
}
else
{
- GLenum format = gl::GetInternalFormatInfo(drawRenderTarget->getInternalFormat()).format;
+ // We don't currently support masking off any other channel than alpha
+ bool maskOffAlpha = colorMaskingNeeded && colorMask.alpha;
result = mBlit->copyTexture(readSRV, readArea, readSize, drawRTV, drawArea, drawSize,
- scissor, format, filter);
+ scissor, destFormatInfo.format, filter, maskOffAlpha);
}
}
@@ -3484,9 +3979,44 @@ gl::Error Renderer11::blitRenderbufferRect(const gl::Rectangle &readRect, const
bool Renderer11::isES3Capable() const
{
- return (d3d11_gl::GetMaximumClientVersion(mFeatureLevel) > 2);
+ return (d3d11_gl::GetMaximumClientVersion(mRenderer11DeviceCaps.featureLevel) > 2);
};
+void Renderer11::onSwap()
+{
+ // Send histogram updates every half hour
+ const double kHistogramUpdateInterval = 30 * 60;
+
+ const double currentTime = ANGLEPlatformCurrent()->monotonicallyIncreasingTime();
+ const double timeSinceLastUpdate = currentTime - mLastHistogramUpdateTime;
+
+ if (timeSinceLastUpdate > kHistogramUpdateInterval)
+ {
+ updateHistograms();
+ mLastHistogramUpdateTime = currentTime;
+ }
+}
+
+void Renderer11::updateHistograms()
+{
+ // Update the buffer CPU memory histogram
+ {
+ size_t sizeSum = 0;
+ for (auto &buffer : mAliveBuffers)
+ {
+ sizeSum += buffer->getTotalCPUBufferMemoryBytes();
+ }
+ const int kOneMegaByte = 1024 * 1024;
+ ANGLE_HISTOGRAM_MEMORY_MB("GPU.ANGLE.Buffer11CPUMemoryMB",
+ static_cast<int>(sizeSum) / kOneMegaByte);
+ }
+}
+
+void Renderer11::onBufferDelete(const Buffer11 *deleted)
+{
+ mAliveBuffers.erase(deleted);
+}
+
ID3D11Texture2D *Renderer11::resolveMultisampledTexture(ID3D11Texture2D *source, unsigned int subresource)
{
D3D11_TEXTURE2D_DESC textureDesc;
@@ -3545,54 +4075,64 @@ bool Renderer11::getLUID(LUID *adapterLuid) const
return true;
}
-VertexConversionType Renderer11::getVertexConversionType(const gl::VertexFormat &vertexFormat) const
+VertexConversionType Renderer11::getVertexConversionType(gl::VertexFormatType vertexFormatType) const
{
- return d3d11::GetVertexFormatInfo(vertexFormat, mFeatureLevel).conversionType;
+ return d3d11::GetVertexFormatInfo(vertexFormatType, mRenderer11DeviceCaps.featureLevel).conversionType;
}
-GLenum Renderer11::getVertexComponentType(const gl::VertexFormat &vertexFormat) const
+GLenum Renderer11::getVertexComponentType(gl::VertexFormatType vertexFormatType) const
{
- return d3d11::GetDXGIFormatInfo(d3d11::GetVertexFormatInfo(vertexFormat, mFeatureLevel).nativeFormat).componentType;
+ return d3d11::GetDXGIFormatInfo(d3d11::GetVertexFormatInfo(vertexFormatType, mRenderer11DeviceCaps.featureLevel).nativeFormat).componentType;
}
-void Renderer11::generateCaps(gl::Caps *outCaps, gl::TextureCapsMap *outTextureCaps, gl::Extensions *outExtensions) const
+void Renderer11::generateCaps(gl::Caps *outCaps, gl::TextureCapsMap *outTextureCaps,
+ gl::Extensions *outExtensions, gl::Limitations *outLimitations) const
{
- d3d11_gl::GenerateCaps(mDevice, mDeviceContext, outCaps, outTextureCaps, outExtensions);
+ d3d11_gl::GenerateCaps(mDevice, mDeviceContext, mRenderer11DeviceCaps, outCaps, outTextureCaps,
+ outExtensions, outLimitations);
}
-Workarounds Renderer11::generateWorkarounds() const
+WorkaroundsD3D Renderer11::generateWorkarounds() const
{
- return d3d11::GenerateWorkarounds(mFeatureLevel);
+ return d3d11::GenerateWorkarounds(mRenderer11DeviceCaps.featureLevel);
}
-void Renderer11::setShaderResource(gl::SamplerType shaderType, UINT resourceSlot, ID3D11ShaderResourceView *srv)
+void Renderer11::createAnnotator()
{
- auto &currentSRVs = (shaderType == gl::SAMPLER_VERTEX ? mCurVertexSRVs : mCurPixelSRVs);
+ // The D3D11 renderer must choose the D3D9 debug annotator because the D3D11 interface
+ // method ID3DUserDefinedAnnotation::GetStatus on desktop builds doesn't work with the Graphics
+ // Diagnostics tools in Visual Studio 2013.
+ // The D3D9 annotator works properly for both D3D11 and D3D9.
+ // Incorrect status reporting can cause ANGLE to log unnecessary debug events.
+#ifdef ANGLE_ENABLE_D3D9
+ mAnnotator = new DebugAnnotator9();
+#else
+ mAnnotator = new DebugAnnotator11();
+#endif
+}
- ASSERT(static_cast<size_t>(resourceSlot) < currentSRVs.size());
- auto &record = currentSRVs[resourceSlot];
+gl::Error Renderer11::clearTextures(gl::SamplerType samplerType, size_t rangeStart, size_t rangeEnd)
+{
+ return mStateManager.clearTextures(samplerType, rangeStart, rangeEnd);
+}
- if (record.srv != reinterpret_cast<uintptr_t>(srv))
+egl::Error Renderer11::getEGLDevice(DeviceImpl **device)
+{
+ if (mEGLDevice == nullptr)
{
- if (shaderType == gl::SAMPLER_VERTEX)
- {
- mDeviceContext->VSSetShaderResources(resourceSlot, 1, &srv);
- }
- else
- {
- mDeviceContext->PSSetShaderResources(resourceSlot, 1, &srv);
- }
+ ASSERT(mDevice != nullptr);
+ mEGLDevice = new DeviceD3D();
+ egl::Error error = mEGLDevice->initialize(reinterpret_cast<void *>(mDevice),
+ EGL_D3D11_DEVICE_ANGLE, EGL_FALSE);
- record.srv = reinterpret_cast<uintptr_t>(srv);
- if (srv)
- {
- record.resource = reinterpret_cast<uintptr_t>(GetViewResource(srv));
- srv->GetDesc(&record.desc);
- }
- else
+ if (error.isError())
{
- record.resource = 0;
+ SafeDelete(mEGLDevice);
+ return error;
}
}
+
+ *device = static_cast<DeviceImpl *>(mEGLDevice);
+ return egl::Error(EGL_SUCCESS);
}
}
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Renderer11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Renderer11.h
index cc7d6c237b..b4e7761ffc 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Renderer11.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Renderer11.h
@@ -18,9 +18,9 @@
#include "libANGLE/renderer/d3d/RenderTargetD3D.h"
#include "libANGLE/renderer/d3d/d3d11/DebugAnnotator11.h"
#include "libANGLE/renderer/d3d/d3d11/InputLayoutCache.h"
+#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h"
#include "libANGLE/renderer/d3d/d3d11/RenderStateCache.h"
-
-struct ID3D11DeviceContext1;
+#include "libANGLE/renderer/d3d/d3d11/StateManager11.h"
namespace gl
{
@@ -28,6 +28,8 @@ class FramebufferAttachment;
struct ImageIndex;
}
+struct ID3D11DeviceContext1;
+
namespace rx
{
@@ -35,12 +37,24 @@ class VertexDataManager;
class IndexDataManager;
class StreamingIndexBufferInterface;
class Blit11;
+class Buffer11;
class Clear11;
class PixelTransfer11;
class RenderTarget11;
class Trim11;
struct PackPixelsParams;
+struct Renderer11DeviceCaps
+{
+ D3D_FEATURE_LEVEL featureLevel;
+ bool supportsDXGI1_2; // Support for DXGI 1.2
+ bool supportsClearView; // Support for ID3D11DeviceContext1::ClearView
+ bool supportsConstantBufferOffsets; // Support for Constant buffer offset
+ UINT B5G6R5support; // Bitfield of D3D11_FORMAT_SUPPORT values for DXGI_FORMAT_B5G6R5_UNORM
+ UINT B4G4R4A4support; // Bitfield of D3D11_FORMAT_SUPPORT values for DXGI_FORMAT_B4G4R4A4_UNORM
+ UINT B5G5R5A1support; // Bitfield of D3D11_FORMAT_SUPPORT values for DXGI_FORMAT_B5G5R5A1_UNORM
+};
+
enum
{
MAX_VERTEX_UNIFORM_VECTORS_D3D11 = 1024,
@@ -64,6 +78,24 @@ enum D3D11InitError
D3D11_INIT_INCOMPATIBLE_DXGI,
// Other initialization error
D3D11_INIT_OTHER_ERROR,
+ // CreateDevice returned E_FAIL
+ D3D11_INIT_CREATEDEVICE_FAIL,
+ // CreateDevice returned E_NOTIMPL
+ D3D11_INIT_CREATEDEVICE_NOTIMPL,
+ // CreateDevice returned E_OUTOFMEMORY
+ D3D11_INIT_CREATEDEVICE_OUTOFMEMORY,
+ // CreateDevice returned DXGI_ERROR_INVALID_CALL
+ D3D11_INIT_CREATEDEVICE_INVALIDCALL,
+ // CreateDevice returned DXGI_ERROR_SDK_COMPONENT_MISSING
+ D3D11_INIT_CREATEDEVICE_COMPONENTMISSING,
+ // CreateDevice returned DXGI_ERROR_WAS_STILL_DRAWING
+ D3D11_INIT_CREATEDEVICE_WASSTILLDRAWING,
+ // CreateDevice returned DXGI_ERROR_NOT_CURRENTLY_AVAILABLE
+ D3D11_INIT_CREATEDEVICE_NOTAVAILABLE,
+ // CreateDevice returned DXGI_ERROR_DEVICE_HUNG
+ D3D11_INIT_CREATEDEVICE_DEVICEHUNG,
+ // CreateDevice returned NULL
+ D3D11_INIT_CREATEDEVICE_NULL,
NUM_D3D11_INIT_ERRORS
};
@@ -73,66 +105,65 @@ class Renderer11 : public RendererD3D
explicit Renderer11(egl::Display *display);
virtual ~Renderer11();
- static Renderer11 *makeRenderer11(Renderer *renderer);
-
egl::Error initialize() override;
virtual bool resetDevice();
egl::ConfigSet generateConfigs() const override;
+ void generateDisplayExtensions(egl::DisplayExtensions *outExtensions) const override;
gl::Error flush() override;
gl::Error finish() override;
- virtual SwapChainD3D *createSwapChain(NativeWindow nativeWindow, HANDLE shareHandle, GLenum backBufferFormat, GLenum depthBufferFormat);
+ SwapChainD3D *createSwapChain(NativeWindow nativeWindow,
+ HANDLE shareHandle,
+ GLenum backBufferFormat,
+ GLenum depthBufferFormat,
+ EGLint orientation) override;
+
+ CompilerImpl *createCompiler() override;
virtual gl::Error generateSwizzle(gl::Texture *texture);
virtual gl::Error setSamplerState(gl::SamplerType type, int index, gl::Texture *texture, const gl::SamplerState &sampler);
virtual gl::Error setTexture(gl::SamplerType type, int index, gl::Texture *texture);
gl::Error setUniformBuffers(const gl::Data &data,
- const GLint vertexUniformBuffers[],
- const GLint fragmentUniformBuffers[]) override;
+ const std::vector<GLint> &vertexUniformBuffers,
+ const std::vector<GLint> &fragmentUniformBuffers) override;
- virtual gl::Error setRasterizerState(const gl::RasterizerState &rasterState);
- gl::Error setBlendState(const gl::Framebuffer *framebuffer, const gl::BlendState &blendState, const gl::ColorF &blendColor,
- unsigned int sampleMask) override;
- virtual gl::Error setDepthStencilState(const gl::DepthStencilState &depthStencilState, int stencilRef,
- int stencilBackRef, bool frontFaceCCW);
-
- virtual void setScissorRectangle(const gl::Rectangle &scissor, bool enabled);
- virtual void setViewport(const gl::Rectangle &viewport, float zNear, float zFar, GLenum drawMode, GLenum frontFace,
- bool ignoreViewport);
+ gl::Error updateState(const gl::Data &data, GLenum drawMode) override;
virtual bool applyPrimitiveType(GLenum mode, GLsizei count, bool usesPointSize);
gl::Error applyRenderTarget(const gl::Framebuffer *frameBuffer) override;
- virtual gl::Error applyShaders(gl::Program *program, const gl::VertexFormat inputLayout[], const gl::Framebuffer *framebuffer,
- bool rasterizerDiscard, bool transformFeedbackActive);
-
- virtual gl::Error applyUniforms(const ProgramImpl &program, const std::vector<gl::LinkedUniform*> &uniformArray);
- virtual gl::Error applyVertexBuffer(const gl::State &state, GLenum mode, GLint first, GLsizei count, GLsizei instances);
- virtual gl::Error applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo);
+ gl::Error applyUniforms(const ProgramD3D &programD3D,
+ GLenum drawMode,
+ const std::vector<D3DUniform *> &uniformArray) override;
+ virtual gl::Error applyVertexBuffer(const gl::State &state,
+ GLenum mode,
+ GLint first,
+ GLsizei count,
+ GLsizei instances,
+ TranslatedIndexData *indexInfo);
+ gl::Error applyIndexBuffer(const gl::Data &data,
+ const GLvoid *indices,
+ GLsizei count,
+ GLenum mode,
+ GLenum type,
+ TranslatedIndexData *indexInfo) override;
void applyTransformFeedbackBuffers(const gl::State &state) override;
- gl::Error drawArrays(const gl::Data &data, GLenum mode, GLsizei count, GLsizei instances, bool usesPointSize) override;
- virtual gl::Error drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices,
- gl::Buffer *elementArrayBuffer, const TranslatedIndexData &indexInfo, GLsizei instances);
-
- virtual void markAllStateDirty();
-
// lost device
bool testDeviceLost() override;
bool testDeviceResettable() override;
- VendorID getVendorId() const override;
std::string getRendererDescription() const override;
- GUID getAdapterIdentifier() const override;
+ DeviceIdentifier getAdapterIdentifier() const override;
virtual unsigned int getReservedVertexUniformVectors() const;
virtual unsigned int getReservedFragmentUniformVectors() const;
virtual unsigned int getReservedVertexUniformBuffers() const;
virtual unsigned int getReservedFragmentUniformBuffers() const;
- virtual bool getShareHandleSupport() const;
- virtual bool getPostSubBufferSupport() const;
+
+ bool getShareHandleSupport() const;
virtual int getMajorShaderModel() const;
int getMinorShaderModel() const override;
@@ -150,30 +181,38 @@ class Renderer11 : public RendererD3D
// RenderTarget creation
virtual gl::Error createRenderTarget(int width, int height, GLenum format, GLsizei samples, RenderTargetD3D **outRT);
+ gl::Error createRenderTargetCopy(RenderTargetD3D *source, RenderTargetD3D **outRT) override;
// Framebuffer creation
- FramebufferImpl *createDefaultFramebuffer(const gl::Framebuffer::Data &data) override;
FramebufferImpl *createFramebuffer(const gl::Framebuffer::Data &data) override;
// Shader creation
- virtual CompilerImpl *createCompiler(const gl::Data &data);
- virtual ShaderImpl *createShader(GLenum type);
- virtual ProgramImpl *createProgram();
+ ShaderImpl *createShader(const gl::Shader::Data &data) override;
+ ProgramImpl *createProgram(const gl::Program::Data &data) override;
// Shader operations
- virtual gl::Error loadExecutable(const void *function, size_t length, ShaderType type,
- const std::vector<gl::LinkedVarying> &transformFeedbackVaryings,
- bool separatedOutputBuffers, ShaderExecutableD3D **outExecutable);
- virtual gl::Error compileToExecutable(gl::InfoLog &infoLog, const std::string &shaderHLSL, ShaderType type,
- const std::vector<gl::LinkedVarying> &transformFeedbackVaryings,
- bool separatedOutputBuffers, const D3DCompilerWorkarounds &workarounds,
- ShaderExecutableD3D **outExectuable);
- virtual UniformStorageD3D *createUniformStorage(size_t storageSize);
+ gl::Error loadExecutable(const void *function,
+ size_t length,
+ ShaderType type,
+ const std::vector<D3DVarying> &streamOutVaryings,
+ bool separatedOutputBuffers,
+ ShaderExecutableD3D **outExecutable) override;
+ gl::Error compileToExecutable(gl::InfoLog &infoLog,
+ const std::string &shaderHLSL,
+ ShaderType type,
+ const std::vector<D3DVarying> &streamOutVaryings,
+ bool separatedOutputBuffers,
+ const D3DCompilerWorkarounds &workarounds,
+ ShaderExecutableD3D **outExectuable) override;
+ UniformStorageD3D *createUniformStorage(size_t storageSize) override;
// Image operations
virtual ImageD3D *createImage();
gl::Error generateMipmap(ImageD3D *dest, ImageD3D *source) override;
+ gl::Error generateMipmapsUsingD3D(TextureStorage *storage,
+ const gl::TextureState &textureState) override;
virtual TextureStorage *createTextureStorage2D(SwapChainD3D *swapChain);
+ TextureStorage *createTextureStorageEGLImage(EGLImageD3D *eglImage) override;
virtual TextureStorage *createTextureStorage2D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels, bool hintLevelZeroOnly);
virtual TextureStorage *createTextureStorageCube(GLenum internalformat, bool renderTarget, int size, int levels, bool hintLevelZeroOnly);
virtual TextureStorage *createTextureStorage3D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels);
@@ -191,7 +230,7 @@ class Renderer11 : public RendererD3D
virtual IndexBuffer *createIndexBuffer();
// Vertex Array creation
- virtual VertexArrayImpl *createVertexArray();
+ VertexArrayImpl *createVertexArray(const gl::VertexArray::Data &data) override;
// Query and Fence creation
virtual QueryImpl *createQuery(GLenum type);
@@ -203,10 +242,13 @@ class Renderer11 : public RendererD3D
// D3D11-renderer specific methods
ID3D11Device *getDevice() { return mDevice; }
+ void *getD3DDevice() override;
ID3D11DeviceContext *getDeviceContext() { return mDeviceContext; };
ID3D11DeviceContext1 *getDeviceContext1IfSupported() { return mDeviceContext1; };
DXGIFactory *getDxgiFactory() { return mDxgiFactory; };
+ RenderStateCache &getStateCache() { return mStateCache; }
+
Blit11 *getBlitter() { return mBlit; }
Clear11 *getClearer() { return mClear; }
@@ -215,64 +257,108 @@ class Renderer11 : public RendererD3D
virtual gl::Error fastCopyBufferToTexture(const gl::PixelUnpackState &unpack, unsigned int offset, RenderTargetD3D *destRenderTarget,
GLenum destinationFormat, GLenum sourcePixelsType, const gl::Box &destArea);
+ void markAllStateDirty();
void unapplyRenderTargets();
void setOneTimeRenderTarget(ID3D11RenderTargetView *renderTargetView);
- gl::Error packPixels(ID3D11Texture2D *readTexture, const PackPixelsParams &params, uint8_t *pixelsOut);
+ gl::Error packPixels(const TextureHelper11 &textureHelper,
+ const PackPixelsParams &params,
+ uint8_t *pixelsOut);
bool getLUID(LUID *adapterLuid) const override;
- virtual VertexConversionType getVertexConversionType(const gl::VertexFormat &vertexFormat) const;
- virtual GLenum getVertexComponentType(const gl::VertexFormat &vertexFormat) const;
-
- gl::Error readTextureData(ID3D11Texture2D *texture, unsigned int subResource, const gl::Rectangle &area, GLenum format,
- GLenum type, GLuint outputPitch, const gl::PixelPackState &pack, uint8_t *pixels);
+ VertexConversionType getVertexConversionType(gl::VertexFormatType vertexFormatType) const override;
+ GLenum getVertexComponentType(gl::VertexFormatType vertexFormatType) const override;
- void setShaderResource(gl::SamplerType shaderType, UINT resourceSlot, ID3D11ShaderResourceView *srv);
+ gl::Error readFromAttachment(const gl::FramebufferAttachment &srcAttachment,
+ const gl::Rectangle &sourceArea,
+ GLenum format,
+ GLenum type,
+ GLuint outputPitch,
+ const gl::PixelPackState &pack,
+ uint8_t *pixels);
gl::Error blitRenderbufferRect(const gl::Rectangle &readRect, const gl::Rectangle &drawRect, RenderTargetD3D *readRenderTarget,
RenderTargetD3D *drawRenderTarget, GLenum filter, const gl::Rectangle *scissor,
bool colorBlit, bool depthBlit, bool stencilBlit);
bool isES3Capable() const;
- D3D_FEATURE_LEVEL getFeatureLevel() const { return mFeatureLevel; };
+ const Renderer11DeviceCaps &getRenderer11DeviceCaps() { return mRenderer11DeviceCaps; };
RendererClass getRendererClass() const override { return RENDERER_D3D11; }
+ InputLayoutCache *getInputLayoutCache() { return &mInputLayoutCache; }
+ StateManager11 *getStateManager() { return &mStateManager; }
- private:
- void generateCaps(gl::Caps *outCaps, gl::TextureCapsMap *outTextureCaps, gl::Extensions *outExtensions) const override;
- Workarounds generateWorkarounds() const override;
+ void onSwap();
+ void onBufferDelete(const Buffer11 *deleted);
+
+ egl::Error getEGLDevice(DeviceImpl **device) override;
- gl::Error drawLineLoop(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer);
- gl::Error drawTriangleFan(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer, int instances);
+ protected:
+ void createAnnotator() override;
+ gl::Error clearTextures(gl::SamplerType samplerType, size_t rangeStart, size_t rangeEnd) override;
+ gl::Error applyShadersImpl(const gl::Data &data, GLenum drawMode) override;
+
+ void syncState(const gl::State &state, const gl::State::DirtyBits &bitmask) override;
+
+ private:
+ gl::Error drawArraysImpl(const gl::Data &data,
+ GLenum mode,
+ GLsizei count,
+ GLsizei instances) override;
+ gl::Error drawElementsImpl(const gl::Data &data,
+ const TranslatedIndexData &indexInfo,
+ GLenum mode,
+ GLsizei count,
+ GLenum type,
+ const GLvoid *indices,
+ GLsizei instances) override;
+
+ void generateCaps(gl::Caps *outCaps, gl::TextureCapsMap *outTextureCaps,
+ gl::Extensions *outExtensions,
+ gl::Limitations *outLimitations) const override;
+
+ WorkaroundsD3D generateWorkarounds() const override;
+
+ gl::Error drawLineLoop(const gl::Data &data,
+ GLsizei count,
+ GLenum type,
+ const GLvoid *indices,
+ const TranslatedIndexData *indexInfo,
+ int instances);
+ gl::Error drawTriangleFan(const gl::Data &data,
+ GLsizei count,
+ GLenum type,
+ const GLvoid *indices,
+ int minIndex,
+ int instances);
ID3D11Texture2D *resolveMultisampledTexture(ID3D11Texture2D *source, unsigned int subresource);
- void unsetConflictingSRVs(gl::SamplerType shaderType, uintptr_t resource, const gl::ImageIndex *index);
+
+ void populateRenderer11DeviceCaps();
+
+ void updateHistograms();
HMODULE mD3d11Module;
HMODULE mDxgiModule;
+ HMODULE mDCompModule;
std::vector<D3D_FEATURE_LEVEL> mAvailableFeatureLevels;
- D3D_DRIVER_TYPE mDriverType;
+ D3D_DRIVER_TYPE mRequestedDriverType;
+ bool mCreatedWithDeviceEXT;
+ DeviceD3D *mEGLDevice;
HLSLCompiler mCompiler;
+ egl::Error initializeD3DDevice();
void initializeDevice();
void releaseDeviceResources();
void release();
+ d3d11::ANGLED3D11DeviceType getDeviceType() const;
+
RenderStateCache mStateCache;
// current render target states
uintptr_t mAppliedRTVs[gl::IMPLEMENTATION_MAX_DRAW_BUFFERS];
uintptr_t mAppliedDSV;
- bool mDepthStencilInitialized;
- bool mRenderTargetDescInitialized;
-
- struct RenderTargetDesc
- {
- size_t width;
- size_t height;
- DXGI_FORMAT format;
- };
- RenderTargetDesc mRenderTargetDesc;
// Currently applied sampler states
std::vector<bool> mForceSetVertexSamplerStates;
@@ -281,42 +367,7 @@ class Renderer11 : public RendererD3D
std::vector<bool> mForceSetPixelSamplerStates;
std::vector<gl::SamplerState> mCurPixelSamplerStates;
- // Currently applied textures
- struct SRVRecord
- {
- uintptr_t srv;
- uintptr_t resource;
- D3D11_SHADER_RESOURCE_VIEW_DESC desc;
- };
- std::vector<SRVRecord> mCurVertexSRVs;
- std::vector<SRVRecord> mCurPixelSRVs;
-
- // Currently applied blend state
- bool mForceSetBlendState;
- gl::BlendState mCurBlendState;
- gl::ColorF mCurBlendColor;
- unsigned int mCurSampleMask;
-
- // Currently applied rasterizer state
- bool mForceSetRasterState;
- gl::RasterizerState mCurRasterState;
-
- // Currently applied depth stencil state
- bool mForceSetDepthStencilState;
- gl::DepthStencilState mCurDepthStencilState;
- int mCurStencilRef;
- int mCurStencilBackRef;
-
- // Currently applied scissor rectangle
- bool mForceSetScissor;
- bool mScissorEnabled;
- gl::Rectangle mCurScissor;
-
- // Currently applied viewport
- bool mForceSetViewport;
- gl::Rectangle mCurViewport;
- float mCurNear;
- float mCurFar;
+ StateManager11 mStateManager;
// Currently applied primitive topology
D3D11_PRIMITIVE_TOPOLOGY mCurrentPrimitiveTopology;
@@ -325,6 +376,7 @@ class Renderer11 : public RendererD3D
ID3D11Buffer *mAppliedIB;
DXGI_FORMAT mAppliedIBFormat;
unsigned int mAppliedIBOffset;
+ bool mAppliedIBChanged;
// Currently applied transform feedback buffers
size_t mAppliedNumXFBBindings;
@@ -342,16 +394,14 @@ class Renderer11 : public RendererD3D
uintptr_t mAppliedGeometryShader;
uintptr_t mAppliedPixelShader;
- dx_VertexConstants mVertexConstants;
- dx_VertexConstants mAppliedVertexConstants;
+ dx_VertexConstants11 mAppliedVertexConstants;
ID3D11Buffer *mDriverConstantBufferVS;
ID3D11Buffer *mCurrentVertexConstantBuffer;
unsigned int mCurrentConstantBufferVS[gl::IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS];
GLintptr mCurrentConstantBufferVSOffset[gl::IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS];
GLsizeiptr mCurrentConstantBufferVSSize[gl::IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS];
- dx_PixelConstants mPixelConstants;
- dx_PixelConstants mAppliedPixelConstants;
+ dx_PixelConstants11 mAppliedPixelConstants;
ID3D11Buffer *mDriverConstantBufferPS;
ID3D11Buffer *mCurrentPixelConstantBuffer;
unsigned int mCurrentConstantBufferPS[gl::IMPLEMENTATION_MAX_FRAGMENT_SHADER_UNIFORM_BUFFERS];
@@ -381,19 +431,26 @@ class Renderer11 : public RendererD3D
// Sync query
ID3D11Query *mSyncQuery;
- // Constant buffer offset support
- bool mSupportsConstantBufferOffsets;
+ // Created objects state tracking
+ std::set<const Buffer11*> mAliveBuffers;
+
+ double mLastHistogramUpdateTime;
ID3D11Device *mDevice;
- D3D_FEATURE_LEVEL mFeatureLevel;
+ Renderer11DeviceCaps mRenderer11DeviceCaps;
ID3D11DeviceContext *mDeviceContext;
ID3D11DeviceContext1 *mDeviceContext1;
IDXGIAdapter *mDxgiAdapter;
DXGI_ADAPTER_DESC mAdapterDescription;
char mDescription[128];
DXGIFactory *mDxgiFactory;
+#if !defined(ANGLE_MINGW32_COMPAT)
+ ID3D11Debug *mDebug;
+#endif
+
+ std::vector<GLuint> mScratchIndexDataBuffer;
- DebugAnnotator11 mAnnotator;
+ mutable Optional<bool> mSupportsShareHandles;
};
}
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/ShaderExecutable11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/ShaderExecutable11.cpp
index 7e64c3183d..4da51afe49 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/ShaderExecutable11.cpp
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/ShaderExecutable11.cpp
@@ -48,12 +48,6 @@ ShaderExecutable11::~ShaderExecutable11()
SafeRelease(mStreamOutExecutable);
}
-ShaderExecutable11 *ShaderExecutable11::makeShaderExecutable11(ShaderExecutableD3D *executable)
-{
- ASSERT(HAS_DYNAMIC_TYPE(ShaderExecutable11*, executable));
- return static_cast<ShaderExecutable11*>(executable);
-}
-
ID3D11VertexShader *ShaderExecutable11::getVertexShader() const
{
return mVertexExecutable;
@@ -83,7 +77,7 @@ UniformStorage11::UniformStorage11(Renderer11 *renderer, size_t initialSize)
if (initialSize > 0)
{
D3D11_BUFFER_DESC constantBufferDescription = {0};
- constantBufferDescription.ByteWidth = initialSize;
+ constantBufferDescription.ByteWidth = static_cast<unsigned int>(initialSize);
constantBufferDescription.Usage = D3D11_USAGE_DYNAMIC;
constantBufferDescription.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
constantBufferDescription.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
@@ -101,10 +95,4 @@ UniformStorage11::~UniformStorage11()
SafeRelease(mConstantBuffer);
}
-const UniformStorage11 *UniformStorage11::makeUniformStorage11(const UniformStorageD3D *uniformStorage)
-{
- ASSERT(HAS_DYNAMIC_TYPE(const UniformStorage11*, uniformStorage));
- return static_cast<const UniformStorage11*>(uniformStorage);
-}
-
}
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/ShaderExecutable11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/ShaderExecutable11.h
index 02558ee4dc..379f39fe53 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/ShaderExecutable11.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/ShaderExecutable11.h
@@ -26,8 +26,6 @@ class ShaderExecutable11 : public ShaderExecutableD3D
virtual ~ShaderExecutable11();
- static ShaderExecutable11 *makeShaderExecutable11(ShaderExecutableD3D *executable);
-
ID3D11PixelShader *getPixelShader() const;
ID3D11VertexShader *getVertexShader() const;
ID3D11GeometryShader *getGeometryShader() const;
@@ -46,8 +44,6 @@ class UniformStorage11 : public UniformStorageD3D
UniformStorage11(Renderer11 *renderer, size_t initialSize);
virtual ~UniformStorage11();
- static const UniformStorage11 *makeUniformStorage11(const UniformStorageD3D *uniformStorage);
-
ID3D11Buffer *getConstantBuffer() const { return mConstantBuffer; }
private:
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/StateManager11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/StateManager11.cpp
new file mode 100644
index 0000000000..aa34fd4de8
--- /dev/null
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/StateManager11.cpp
@@ -0,0 +1,1040 @@
+//
+// 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.
+//
+
+// StateManager11.cpp: Defines a class for caching D3D11 state
+
+#include "libANGLE/renderer/d3d/d3d11/StateManager11.h"
+
+#include "common/BitSetIterator.h"
+#include "common/utilities.h"
+#include "libANGLE/renderer/d3d/d3d11/Framebuffer11.h"
+#include "libANGLE/renderer/d3d/d3d11/Renderer11.h"
+#include "libANGLE/renderer/d3d/d3d11/RenderTarget11.h"
+
+namespace rx
+{
+
+namespace
+{
+bool ImageIndexConflictsWithSRV(const gl::ImageIndex &index, D3D11_SHADER_RESOURCE_VIEW_DESC desc)
+{
+ unsigned mipLevel = index.mipIndex;
+ unsigned layerIndex = index.layerIndex;
+ GLenum type = index.type;
+
+ switch (desc.ViewDimension)
+ {
+ case D3D11_SRV_DIMENSION_TEXTURE2D:
+ {
+ unsigned maxSrvMip = desc.Texture2D.MipLevels + desc.Texture2D.MostDetailedMip;
+ maxSrvMip = (desc.Texture2D.MipLevels == -1) ? INT_MAX : maxSrvMip;
+
+ unsigned mipMin = index.mipIndex;
+ unsigned mipMax = (layerIndex == -1) ? INT_MAX : layerIndex;
+
+ return type == GL_TEXTURE_2D &&
+ gl::RangeUI(mipMin, mipMax)
+ .intersects(gl::RangeUI(desc.Texture2D.MostDetailedMip, maxSrvMip));
+ }
+
+ case D3D11_SRV_DIMENSION_TEXTURE2DARRAY:
+ {
+ unsigned maxSrvMip =
+ desc.Texture2DArray.MipLevels + desc.Texture2DArray.MostDetailedMip;
+ maxSrvMip = (desc.Texture2DArray.MipLevels == -1) ? INT_MAX : maxSrvMip;
+
+ unsigned maxSlice = desc.Texture2DArray.FirstArraySlice + desc.Texture2DArray.ArraySize;
+
+ // Cube maps can be mapped to Texture2DArray SRVs
+ return (type == GL_TEXTURE_2D_ARRAY || gl::IsCubeMapTextureTarget(type)) &&
+ desc.Texture2DArray.MostDetailedMip <= mipLevel && mipLevel < maxSrvMip &&
+ desc.Texture2DArray.FirstArraySlice <= layerIndex && layerIndex < maxSlice;
+ }
+
+ case D3D11_SRV_DIMENSION_TEXTURECUBE:
+ {
+ unsigned maxSrvMip = desc.TextureCube.MipLevels + desc.TextureCube.MostDetailedMip;
+ maxSrvMip = (desc.TextureCube.MipLevels == -1) ? INT_MAX : maxSrvMip;
+
+ return gl::IsCubeMapTextureTarget(type) &&
+ desc.TextureCube.MostDetailedMip <= mipLevel && mipLevel < maxSrvMip;
+ }
+
+ case D3D11_SRV_DIMENSION_TEXTURE3D:
+ {
+ unsigned maxSrvMip = desc.Texture3D.MipLevels + desc.Texture3D.MostDetailedMip;
+ maxSrvMip = (desc.Texture3D.MipLevels == -1) ? INT_MAX : maxSrvMip;
+
+ return type == GL_TEXTURE_3D && desc.Texture3D.MostDetailedMip <= mipLevel &&
+ mipLevel < maxSrvMip;
+ }
+ default:
+ // We only handle the cases corresponding to valid image indexes
+ UNIMPLEMENTED();
+ }
+
+ return false;
+}
+
+// Does *not* increment the resource ref count!!
+ID3D11Resource *GetViewResource(ID3D11View *view)
+{
+ ID3D11Resource *resource = NULL;
+ ASSERT(view);
+ view->GetResource(&resource);
+ resource->Release();
+ return resource;
+}
+
+} // anonymous namespace
+
+void StateManager11::SRVCache::update(size_t resourceIndex, ID3D11ShaderResourceView *srv)
+{
+ ASSERT(resourceIndex < mCurrentSRVs.size());
+ SRVRecord *record = &mCurrentSRVs[resourceIndex];
+
+ record->srv = reinterpret_cast<uintptr_t>(srv);
+ if (srv)
+ {
+ record->resource = reinterpret_cast<uintptr_t>(GetViewResource(srv));
+ srv->GetDesc(&record->desc);
+ mHighestUsedSRV = std::max(resourceIndex + 1, mHighestUsedSRV);
+ }
+ else
+ {
+ record->resource = 0;
+
+ if (resourceIndex + 1 == mHighestUsedSRV)
+ {
+ do
+ {
+ --mHighestUsedSRV;
+ } while (mHighestUsedSRV > 0 && mCurrentSRVs[mHighestUsedSRV].srv == 0);
+ }
+ }
+}
+
+void StateManager11::SRVCache::clear()
+{
+ if (mCurrentSRVs.empty())
+ {
+ return;
+ }
+
+ memset(&mCurrentSRVs[0], 0, sizeof(SRVRecord) * mCurrentSRVs.size());
+ mHighestUsedSRV = 0;
+}
+
+StateManager11::StateManager11(Renderer11 *renderer)
+ : mRenderer(renderer),
+ mBlendStateIsDirty(false),
+ mCurBlendColor(0, 0, 0, 0),
+ mCurSampleMask(0),
+ mDepthStencilStateIsDirty(false),
+ mCurStencilRef(0),
+ mCurStencilBackRef(0),
+ mCurStencilSize(0),
+ mRasterizerStateIsDirty(false),
+ mScissorStateIsDirty(false),
+ mCurScissorEnabled(false),
+ mCurScissorRect(),
+ mViewportStateIsDirty(false),
+ mCurViewport(),
+ mCurNear(0.0f),
+ mCurFar(0.0f),
+ mViewportBounds(),
+ mCurPresentPathFastEnabled(false),
+ mCurPresentPathFastColorBufferHeight(0),
+ mAppliedDSV(angle::DirtyPointer)
+{
+ mCurBlendState.blend = false;
+ mCurBlendState.sourceBlendRGB = GL_ONE;
+ mCurBlendState.destBlendRGB = GL_ZERO;
+ mCurBlendState.sourceBlendAlpha = GL_ONE;
+ mCurBlendState.destBlendAlpha = GL_ZERO;
+ mCurBlendState.blendEquationRGB = GL_FUNC_ADD;
+ mCurBlendState.blendEquationAlpha = GL_FUNC_ADD;
+ mCurBlendState.colorMaskRed = true;
+ mCurBlendState.colorMaskBlue = true;
+ mCurBlendState.colorMaskGreen = true;
+ mCurBlendState.colorMaskAlpha = true;
+ mCurBlendState.sampleAlphaToCoverage = false;
+ mCurBlendState.dither = false;
+
+ mCurDepthStencilState.depthTest = false;
+ mCurDepthStencilState.depthFunc = GL_LESS;
+ mCurDepthStencilState.depthMask = true;
+ mCurDepthStencilState.stencilTest = false;
+ mCurDepthStencilState.stencilMask = true;
+ mCurDepthStencilState.stencilFail = GL_KEEP;
+ mCurDepthStencilState.stencilPassDepthFail = GL_KEEP;
+ mCurDepthStencilState.stencilPassDepthPass = GL_KEEP;
+ mCurDepthStencilState.stencilWritemask = static_cast<GLuint>(-1);
+ mCurDepthStencilState.stencilBackFunc = GL_ALWAYS;
+ mCurDepthStencilState.stencilBackMask = static_cast<GLuint>(-1);
+ mCurDepthStencilState.stencilBackFail = GL_KEEP;
+ mCurDepthStencilState.stencilBackPassDepthFail = GL_KEEP;
+ mCurDepthStencilState.stencilBackPassDepthPass = GL_KEEP;
+ mCurDepthStencilState.stencilBackWritemask = static_cast<GLuint>(-1);
+
+ mCurRasterState.rasterizerDiscard = false;
+ mCurRasterState.cullFace = false;
+ mCurRasterState.cullMode = GL_BACK;
+ mCurRasterState.frontFace = GL_CCW;
+ mCurRasterState.polygonOffsetFill = false;
+ mCurRasterState.polygonOffsetFactor = 0.0f;
+ mCurRasterState.polygonOffsetUnits = 0.0f;
+ mCurRasterState.pointDrawMode = false;
+ mCurRasterState.multiSample = false;
+}
+
+StateManager11::~StateManager11()
+{
+}
+
+void StateManager11::updateStencilSizeIfChanged(bool depthStencilInitialized,
+ unsigned int stencilSize)
+{
+ if (!depthStencilInitialized || stencilSize != mCurStencilSize)
+ {
+ mCurStencilSize = stencilSize;
+ mDepthStencilStateIsDirty = true;
+ }
+}
+
+void StateManager11::setViewportBounds(const int width, const int height)
+{
+ if (mRenderer->getRenderer11DeviceCaps().featureLevel <= D3D_FEATURE_LEVEL_9_3 &&
+ (mViewportBounds.width != width || mViewportBounds.height != height))
+ {
+ mViewportBounds = gl::Extents(width, height, 1);
+ mViewportStateIsDirty = true;
+ }
+}
+
+void StateManager11::updatePresentPath(bool presentPathFastActive,
+ const gl::FramebufferAttachment *framebufferAttachment)
+{
+ const int colorBufferHeight =
+ framebufferAttachment ? framebufferAttachment->getSize().height : 0;
+
+ if ((mCurPresentPathFastEnabled != presentPathFastActive) ||
+ (presentPathFastActive && (colorBufferHeight != mCurPresentPathFastColorBufferHeight)))
+ {
+ mCurPresentPathFastEnabled = presentPathFastActive;
+ mCurPresentPathFastColorBufferHeight = colorBufferHeight;
+ mViewportStateIsDirty = true; // Viewport may need to be vertically inverted
+ mScissorStateIsDirty = true; // Scissor rect may need to be vertically inverted
+ mRasterizerStateIsDirty = true; // Cull Mode may need to be inverted
+ }
+}
+
+void StateManager11::syncState(const gl::State &state, const gl::State::DirtyBits &dirtyBits)
+{
+ if (!dirtyBits.any())
+ {
+ return;
+ }
+
+ for (unsigned int dirtyBit : angle::IterateBitSet(dirtyBits))
+ {
+ switch (dirtyBit)
+ {
+ case gl::State::DIRTY_BIT_BLEND_EQUATIONS:
+ {
+ const gl::BlendState &blendState = state.getBlendState();
+ if (blendState.blendEquationRGB != mCurBlendState.blendEquationRGB ||
+ blendState.blendEquationAlpha != mCurBlendState.blendEquationAlpha)
+ {
+ mBlendStateIsDirty = true;
+ }
+ break;
+ }
+ case gl::State::DIRTY_BIT_BLEND_FUNCS:
+ {
+ const gl::BlendState &blendState = state.getBlendState();
+ if (blendState.sourceBlendRGB != mCurBlendState.sourceBlendRGB ||
+ blendState.destBlendRGB != mCurBlendState.destBlendRGB ||
+ blendState.sourceBlendAlpha != mCurBlendState.sourceBlendAlpha ||
+ blendState.destBlendAlpha != mCurBlendState.destBlendAlpha)
+ {
+ mBlendStateIsDirty = true;
+ }
+ break;
+ }
+ case gl::State::DIRTY_BIT_BLEND_ENABLED:
+ if (state.getBlendState().blend != mCurBlendState.blend)
+ {
+ mBlendStateIsDirty = true;
+ }
+ break;
+ case gl::State::DIRTY_BIT_SAMPLE_ALPHA_TO_COVERAGE_ENABLED:
+ if (state.getBlendState().sampleAlphaToCoverage !=
+ mCurBlendState.sampleAlphaToCoverage)
+ {
+ mBlendStateIsDirty = true;
+ }
+ break;
+ case gl::State::DIRTY_BIT_DITHER_ENABLED:
+ if (state.getBlendState().dither != mCurBlendState.dither)
+ {
+ mBlendStateIsDirty = true;
+ }
+ break;
+ case gl::State::DIRTY_BIT_COLOR_MASK:
+ {
+ const gl::BlendState &blendState = state.getBlendState();
+ if (blendState.colorMaskRed != mCurBlendState.colorMaskRed ||
+ blendState.colorMaskGreen != mCurBlendState.colorMaskGreen ||
+ blendState.colorMaskBlue != mCurBlendState.colorMaskBlue ||
+ blendState.colorMaskAlpha != mCurBlendState.colorMaskAlpha)
+ {
+ mBlendStateIsDirty = true;
+ }
+ break;
+ }
+ case gl::State::DIRTY_BIT_BLEND_COLOR:
+ if (state.getBlendColor() != mCurBlendColor)
+ {
+ mBlendStateIsDirty = true;
+ }
+ break;
+ case gl::State::DIRTY_BIT_DEPTH_MASK:
+ if (state.getDepthStencilState().depthMask != mCurDepthStencilState.depthMask)
+ {
+ mDepthStencilStateIsDirty = true;
+ }
+ break;
+ case gl::State::DIRTY_BIT_DEPTH_TEST_ENABLED:
+ if (state.getDepthStencilState().depthTest != mCurDepthStencilState.depthTest)
+ {
+ mDepthStencilStateIsDirty = true;
+ }
+ break;
+ case gl::State::DIRTY_BIT_DEPTH_FUNC:
+ if (state.getDepthStencilState().depthFunc != mCurDepthStencilState.depthFunc)
+ {
+ mDepthStencilStateIsDirty = true;
+ }
+ break;
+ case gl::State::DIRTY_BIT_STENCIL_TEST_ENABLED:
+ if (state.getDepthStencilState().stencilTest != mCurDepthStencilState.stencilTest)
+ {
+ mDepthStencilStateIsDirty = true;
+ }
+ break;
+ case gl::State::DIRTY_BIT_STENCIL_FUNCS_FRONT:
+ {
+ const gl::DepthStencilState &depthStencil = state.getDepthStencilState();
+ if (depthStencil.stencilFunc != mCurDepthStencilState.stencilFunc ||
+ depthStencil.stencilMask != mCurDepthStencilState.stencilMask ||
+ state.getStencilRef() != mCurStencilRef)
+ {
+ mDepthStencilStateIsDirty = true;
+ }
+ break;
+ }
+ case gl::State::DIRTY_BIT_STENCIL_FUNCS_BACK:
+ {
+ const gl::DepthStencilState &depthStencil = state.getDepthStencilState();
+ if (depthStencil.stencilBackFunc != mCurDepthStencilState.stencilBackFunc ||
+ depthStencil.stencilBackMask != mCurDepthStencilState.stencilBackMask ||
+ state.getStencilBackRef() != mCurStencilBackRef)
+ {
+ mDepthStencilStateIsDirty = true;
+ }
+ break;
+ }
+ case gl::State::DIRTY_BIT_STENCIL_WRITEMASK_FRONT:
+ if (state.getDepthStencilState().stencilWritemask !=
+ mCurDepthStencilState.stencilWritemask)
+ {
+ mDepthStencilStateIsDirty = true;
+ }
+ break;
+ case gl::State::DIRTY_BIT_STENCIL_WRITEMASK_BACK:
+ if (state.getDepthStencilState().stencilBackWritemask !=
+ mCurDepthStencilState.stencilBackWritemask)
+ {
+ mDepthStencilStateIsDirty = true;
+ }
+ break;
+ case gl::State::DIRTY_BIT_STENCIL_OPS_FRONT:
+ {
+ const gl::DepthStencilState &depthStencil = state.getDepthStencilState();
+ if (depthStencil.stencilFail != mCurDepthStencilState.stencilFail ||
+ depthStencil.stencilPassDepthFail !=
+ mCurDepthStencilState.stencilPassDepthFail ||
+ depthStencil.stencilPassDepthPass != mCurDepthStencilState.stencilPassDepthPass)
+ {
+ mDepthStencilStateIsDirty = true;
+ }
+ break;
+ }
+ case gl::State::DIRTY_BIT_STENCIL_OPS_BACK:
+ {
+ const gl::DepthStencilState &depthStencil = state.getDepthStencilState();
+ if (depthStencil.stencilBackFail != mCurDepthStencilState.stencilBackFail ||
+ depthStencil.stencilBackPassDepthFail !=
+ mCurDepthStencilState.stencilBackPassDepthFail ||
+ depthStencil.stencilBackPassDepthPass !=
+ mCurDepthStencilState.stencilBackPassDepthPass)
+ {
+ mDepthStencilStateIsDirty = true;
+ }
+ break;
+ }
+ case gl::State::DIRTY_BIT_CULL_FACE_ENABLED:
+ if (state.getRasterizerState().cullFace != mCurRasterState.cullFace)
+ {
+ mRasterizerStateIsDirty = true;
+ }
+ break;
+ case gl::State::DIRTY_BIT_CULL_FACE:
+ if (state.getRasterizerState().cullMode != mCurRasterState.cullMode)
+ {
+ mRasterizerStateIsDirty = true;
+ }
+ break;
+ case gl::State::DIRTY_BIT_FRONT_FACE:
+ if (state.getRasterizerState().frontFace != mCurRasterState.frontFace)
+ {
+ mRasterizerStateIsDirty = true;
+ }
+ break;
+ case gl::State::DIRTY_BIT_POLYGON_OFFSET_FILL_ENABLED:
+ if (state.getRasterizerState().polygonOffsetFill !=
+ mCurRasterState.polygonOffsetFill)
+ {
+ mRasterizerStateIsDirty = true;
+ }
+ break;
+ case gl::State::DIRTY_BIT_POLYGON_OFFSET:
+ {
+ const gl::RasterizerState &rasterState = state.getRasterizerState();
+ if (rasterState.polygonOffsetFactor != mCurRasterState.polygonOffsetFactor ||
+ rasterState.polygonOffsetUnits != mCurRasterState.polygonOffsetUnits)
+ {
+ mRasterizerStateIsDirty = true;
+ }
+ break;
+ }
+ case gl::State::DIRTY_BIT_RASTERIZER_DISCARD_ENABLED:
+ if (state.getRasterizerState().rasterizerDiscard !=
+ mCurRasterState.rasterizerDiscard)
+ {
+ mRasterizerStateIsDirty = true;
+ }
+ break;
+ case gl::State::DIRTY_BIT_SCISSOR:
+ if (state.getScissor() != mCurScissorRect)
+ {
+ mScissorStateIsDirty = true;
+ }
+ break;
+ case gl::State::DIRTY_BIT_SCISSOR_TEST_ENABLED:
+ if (state.isScissorTestEnabled() != mCurScissorEnabled)
+ {
+ mScissorStateIsDirty = true;
+ // Rasterizer state update needs mCurScissorsEnabled and updates when it changes
+ mRasterizerStateIsDirty = true;
+ }
+ break;
+ case gl::State::DIRTY_BIT_DEPTH_RANGE:
+ if (state.getNearPlane() != mCurNear || state.getFarPlane() != mCurFar)
+ {
+ mViewportStateIsDirty = true;
+ }
+ break;
+ case gl::State::DIRTY_BIT_VIEWPORT:
+ if (state.getViewport() != mCurViewport)
+ {
+ mViewportStateIsDirty = true;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+gl::Error StateManager11::setBlendState(const gl::Framebuffer *framebuffer,
+ const gl::BlendState &blendState,
+ const gl::ColorF &blendColor,
+ unsigned int sampleMask)
+{
+ if (!mBlendStateIsDirty && sampleMask == mCurSampleMask)
+ {
+ return gl::Error(GL_NO_ERROR);
+ }
+
+ ID3D11BlendState *dxBlendState = nullptr;
+ gl::Error error =
+ mRenderer->getStateCache().getBlendState(framebuffer, blendState, &dxBlendState);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ ASSERT(dxBlendState != nullptr);
+
+ float blendColors[4] = {0.0f};
+ if (blendState.sourceBlendRGB != GL_CONSTANT_ALPHA &&
+ blendState.sourceBlendRGB != GL_ONE_MINUS_CONSTANT_ALPHA &&
+ blendState.destBlendRGB != GL_CONSTANT_ALPHA &&
+ blendState.destBlendRGB != GL_ONE_MINUS_CONSTANT_ALPHA)
+ {
+ blendColors[0] = blendColor.red;
+ blendColors[1] = blendColor.green;
+ blendColors[2] = blendColor.blue;
+ blendColors[3] = blendColor.alpha;
+ }
+ else
+ {
+ blendColors[0] = blendColor.alpha;
+ blendColors[1] = blendColor.alpha;
+ blendColors[2] = blendColor.alpha;
+ blendColors[3] = blendColor.alpha;
+ }
+
+ mRenderer->getDeviceContext()->OMSetBlendState(dxBlendState, blendColors, sampleMask);
+
+ mCurBlendState = blendState;
+ mCurBlendColor = blendColor;
+ mCurSampleMask = sampleMask;
+
+ mBlendStateIsDirty = false;
+
+ return error;
+}
+
+gl::Error StateManager11::setDepthStencilState(const gl::State &glState)
+{
+ const auto &fbo = *glState.getDrawFramebuffer();
+
+ // Disable the depth test/depth write if we are using a stencil-only attachment.
+ // This is because ANGLE emulates stencil-only with D24S8 on D3D11 - we should neither read
+ // nor write to the unused depth part of this emulated texture.
+ bool disableDepth = (!fbo.hasDepth() && fbo.hasStencil());
+
+ // Similarly we disable the stencil portion of the DS attachment if the app only binds depth.
+ bool disableStencil = (fbo.hasDepth() && !fbo.hasStencil());
+
+ // CurDisableDepth/Stencil are reset automatically after we call forceSetDepthStencilState.
+ if (!mDepthStencilStateIsDirty && mCurDisableDepth.valid() &&
+ disableDepth == mCurDisableDepth.value() && mCurDisableStencil.valid() &&
+ disableStencil == mCurDisableStencil.value())
+ {
+ return gl::Error(GL_NO_ERROR);
+ }
+
+ const auto &depthStencilState = glState.getDepthStencilState();
+ int stencilRef = glState.getStencilRef();
+ int stencilBackRef = glState.getStencilBackRef();
+
+ // get the maximum size of the stencil ref
+ unsigned int maxStencil = 0;
+ if (depthStencilState.stencilTest && mCurStencilSize > 0)
+ {
+ maxStencil = (1 << mCurStencilSize) - 1;
+ }
+ ASSERT((depthStencilState.stencilWritemask & maxStencil) ==
+ (depthStencilState.stencilBackWritemask & maxStencil));
+ ASSERT(stencilRef == stencilBackRef);
+ ASSERT((depthStencilState.stencilMask & maxStencil) ==
+ (depthStencilState.stencilBackMask & maxStencil));
+
+ ID3D11DepthStencilState *dxDepthStencilState = NULL;
+ gl::Error error = mRenderer->getStateCache().getDepthStencilState(
+ depthStencilState, disableDepth, disableStencil, &dxDepthStencilState);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ ASSERT(dxDepthStencilState);
+
+ // Max D3D11 stencil reference value is 0xFF,
+ // corresponding to the max 8 bits in a stencil buffer
+ // GL specifies we should clamp the ref value to the
+ // nearest bit depth when doing stencil ops
+ static_assert(D3D11_DEFAULT_STENCIL_READ_MASK == 0xFF,
+ "Unexpected value of D3D11_DEFAULT_STENCIL_READ_MASK");
+ static_assert(D3D11_DEFAULT_STENCIL_WRITE_MASK == 0xFF,
+ "Unexpected value of D3D11_DEFAULT_STENCIL_WRITE_MASK");
+ UINT dxStencilRef = std::min<UINT>(stencilRef, 0xFFu);
+
+ mRenderer->getDeviceContext()->OMSetDepthStencilState(dxDepthStencilState, dxStencilRef);
+
+ mCurDepthStencilState = depthStencilState;
+ mCurStencilRef = stencilRef;
+ mCurStencilBackRef = stencilBackRef;
+ mCurDisableDepth = disableDepth;
+ mCurDisableStencil = disableStencil;
+
+ mDepthStencilStateIsDirty = false;
+
+ return gl::Error(GL_NO_ERROR);
+}
+
+gl::Error StateManager11::setRasterizerState(const gl::RasterizerState &rasterState)
+{
+ if (!mRasterizerStateIsDirty)
+ {
+ return gl::Error(GL_NO_ERROR);
+ }
+
+ ID3D11RasterizerState *dxRasterState = nullptr;
+ gl::Error error(GL_NO_ERROR);
+
+ if (mCurPresentPathFastEnabled)
+ {
+ gl::RasterizerState modifiedRasterState = rasterState;
+
+ // If prseent path fast is active then we need invert the front face state.
+ // This ensures that both gl_FrontFacing is correct, and front/back culling
+ // is performed correctly.
+ if (modifiedRasterState.frontFace == GL_CCW)
+ {
+ modifiedRasterState.frontFace = GL_CW;
+ }
+ else
+ {
+ ASSERT(modifiedRasterState.frontFace == GL_CW);
+ modifiedRasterState.frontFace = GL_CCW;
+ }
+
+ error = mRenderer->getStateCache().getRasterizerState(modifiedRasterState,
+ mCurScissorEnabled, &dxRasterState);
+ }
+ else
+ {
+ error = mRenderer->getStateCache().getRasterizerState(rasterState, mCurScissorEnabled,
+ &dxRasterState);
+ }
+
+ if (error.isError())
+ {
+ return error;
+ }
+
+ mRenderer->getDeviceContext()->RSSetState(dxRasterState);
+
+ mCurRasterState = rasterState;
+ mRasterizerStateIsDirty = false;
+
+ return error;
+}
+
+void StateManager11::setScissorRectangle(const gl::Rectangle &scissor, bool enabled)
+{
+ if (!mScissorStateIsDirty)
+ return;
+
+ int modifiedScissorY = scissor.y;
+ if (mCurPresentPathFastEnabled)
+ {
+ modifiedScissorY = mCurPresentPathFastColorBufferHeight - scissor.height - scissor.y;
+ }
+
+ if (enabled)
+ {
+ D3D11_RECT rect;
+ rect.left = std::max(0, scissor.x);
+ rect.top = std::max(0, modifiedScissorY);
+ rect.right = scissor.x + std::max(0, scissor.width);
+ rect.bottom = modifiedScissorY + std::max(0, scissor.height);
+
+ mRenderer->getDeviceContext()->RSSetScissorRects(1, &rect);
+ }
+
+ mCurScissorRect = scissor;
+ mCurScissorEnabled = enabled;
+ mScissorStateIsDirty = false;
+}
+
+void StateManager11::setViewport(const gl::Caps *caps,
+ const gl::Rectangle &viewport,
+ float zNear,
+ float zFar)
+{
+ if (!mViewportStateIsDirty)
+ return;
+
+ float actualZNear = gl::clamp01(zNear);
+ float actualZFar = gl::clamp01(zFar);
+
+ int dxMaxViewportBoundsX = static_cast<int>(caps->maxViewportWidth);
+ int dxMaxViewportBoundsY = static_cast<int>(caps->maxViewportHeight);
+ int dxMinViewportBoundsX = -dxMaxViewportBoundsX;
+ int dxMinViewportBoundsY = -dxMaxViewportBoundsY;
+
+ if (mRenderer->getRenderer11DeviceCaps().featureLevel <= D3D_FEATURE_LEVEL_9_3)
+ {
+ // Feature Level 9 viewports shouldn't exceed the dimensions of the rendertarget.
+ dxMaxViewportBoundsX = static_cast<int>(mViewportBounds.width);
+ dxMaxViewportBoundsY = static_cast<int>(mViewportBounds.height);
+ dxMinViewportBoundsX = 0;
+ dxMinViewportBoundsY = 0;
+ }
+
+ int dxViewportTopLeftX = gl::clamp(viewport.x, dxMinViewportBoundsX, dxMaxViewportBoundsX);
+ int dxViewportTopLeftY = gl::clamp(viewport.y, dxMinViewportBoundsY, dxMaxViewportBoundsY);
+ int dxViewportWidth = gl::clamp(viewport.width, 0, dxMaxViewportBoundsX - dxViewportTopLeftX);
+ int dxViewportHeight = gl::clamp(viewport.height, 0, dxMaxViewportBoundsY - dxViewportTopLeftY);
+
+ D3D11_VIEWPORT dxViewport;
+ dxViewport.TopLeftX = static_cast<float>(dxViewportTopLeftX);
+
+ if (mCurPresentPathFastEnabled)
+ {
+ // When present path fast is active and we're rendering to framebuffer 0, we must invert
+ // the viewport in Y-axis.
+ // NOTE: We delay the inversion until right before the call to RSSetViewports, and leave
+ // dxViewportTopLeftY unchanged. This allows us to calculate viewAdjust below using the
+ // unaltered dxViewportTopLeftY value.
+ dxViewport.TopLeftY = static_cast<float>(mCurPresentPathFastColorBufferHeight -
+ dxViewportTopLeftY - dxViewportHeight);
+ }
+ else
+ {
+ dxViewport.TopLeftY = static_cast<float>(dxViewportTopLeftY);
+ }
+
+ dxViewport.Width = static_cast<float>(dxViewportWidth);
+ dxViewport.Height = static_cast<float>(dxViewportHeight);
+ dxViewport.MinDepth = actualZNear;
+ dxViewport.MaxDepth = actualZFar;
+
+ mRenderer->getDeviceContext()->RSSetViewports(1, &dxViewport);
+
+ mCurViewport = viewport;
+ mCurNear = actualZNear;
+ mCurFar = actualZFar;
+
+ // On Feature Level 9_*, we must emulate large and/or negative viewports in the shaders
+ // using viewAdjust (like the D3D9 renderer).
+ if (mRenderer->getRenderer11DeviceCaps().featureLevel <= D3D_FEATURE_LEVEL_9_3)
+ {
+ mVertexConstants.viewAdjust[0] = static_cast<float>((viewport.width - dxViewportWidth) +
+ 2 * (viewport.x - dxViewportTopLeftX)) /
+ dxViewport.Width;
+ mVertexConstants.viewAdjust[1] = static_cast<float>((viewport.height - dxViewportHeight) +
+ 2 * (viewport.y - dxViewportTopLeftY)) /
+ dxViewport.Height;
+ mVertexConstants.viewAdjust[2] = static_cast<float>(viewport.width) / dxViewport.Width;
+ mVertexConstants.viewAdjust[3] = static_cast<float>(viewport.height) / dxViewport.Height;
+ }
+
+ mPixelConstants.viewCoords[0] = viewport.width * 0.5f;
+ mPixelConstants.viewCoords[1] = viewport.height * 0.5f;
+ mPixelConstants.viewCoords[2] = viewport.x + (viewport.width * 0.5f);
+ mPixelConstants.viewCoords[3] = viewport.y + (viewport.height * 0.5f);
+
+ // Instanced pointsprite emulation requires ViewCoords to be defined in the
+ // the vertex shader.
+ mVertexConstants.viewCoords[0] = mPixelConstants.viewCoords[0];
+ mVertexConstants.viewCoords[1] = mPixelConstants.viewCoords[1];
+ mVertexConstants.viewCoords[2] = mPixelConstants.viewCoords[2];
+ mVertexConstants.viewCoords[3] = mPixelConstants.viewCoords[3];
+
+ mPixelConstants.depthFront[0] = (actualZFar - actualZNear) * 0.5f;
+ mPixelConstants.depthFront[1] = (actualZNear + actualZFar) * 0.5f;
+
+ mVertexConstants.depthRange[0] = actualZNear;
+ mVertexConstants.depthRange[1] = actualZFar;
+ mVertexConstants.depthRange[2] = actualZFar - actualZNear;
+
+ mPixelConstants.depthRange[0] = actualZNear;
+ mPixelConstants.depthRange[1] = actualZFar;
+ mPixelConstants.depthRange[2] = actualZFar - actualZNear;
+
+ mPixelConstants.viewScale[0] = 1.0f;
+ mPixelConstants.viewScale[1] = mCurPresentPathFastEnabled ? 1.0f : -1.0f;
+ mPixelConstants.viewScale[2] = 1.0f;
+ mPixelConstants.viewScale[3] = 1.0f;
+
+ mVertexConstants.viewScale[0] = mPixelConstants.viewScale[0];
+ mVertexConstants.viewScale[1] = mPixelConstants.viewScale[1];
+ mVertexConstants.viewScale[2] = mPixelConstants.viewScale[2];
+ mVertexConstants.viewScale[3] = mPixelConstants.viewScale[3];
+
+ mViewportStateIsDirty = false;
+}
+
+void StateManager11::invalidateRenderTarget()
+{
+ for (auto &appliedRTV : mAppliedRTVs)
+ {
+ appliedRTV = angle::DirtyPointer;
+ }
+ mAppliedDSV = angle::DirtyPointer;
+}
+
+void StateManager11::invalidateEverything()
+{
+ mBlendStateIsDirty = true;
+ mDepthStencilStateIsDirty = true;
+ mRasterizerStateIsDirty = true;
+ mScissorStateIsDirty = true;
+ mViewportStateIsDirty = true;
+
+ // We reset the current SRV data because it might not be in sync with D3D's state
+ // anymore. For example when a currently used SRV is used as an RTV, D3D silently
+ // remove it from its state.
+ mCurVertexSRVs.clear();
+ mCurPixelSRVs.clear();
+
+ invalidateRenderTarget();
+}
+
+bool StateManager11::setRenderTargets(const RenderTargetArray &renderTargets,
+ ID3D11DepthStencilView *depthStencil)
+{
+ // TODO(jmadill): Use context caps?
+ UINT drawBuffers = mRenderer->getRendererCaps().maxDrawBuffers;
+
+ // Apply the render target and depth stencil
+ size_t arraySize = sizeof(uintptr_t) * drawBuffers;
+ if (memcmp(renderTargets.data(), mAppliedRTVs.data(), arraySize) == 0 &&
+ reinterpret_cast<uintptr_t>(depthStencil) == mAppliedDSV)
+ {
+ return false;
+ }
+
+ // The D3D11 blend state is heavily dependent on the current render target.
+ mBlendStateIsDirty = true;
+
+ for (UINT rtIndex = 0; rtIndex < drawBuffers; rtIndex++)
+ {
+ mAppliedRTVs[rtIndex] = reinterpret_cast<uintptr_t>(renderTargets[rtIndex]);
+ }
+ mAppliedDSV = reinterpret_cast<uintptr_t>(depthStencil);
+
+ mRenderer->getDeviceContext()->OMSetRenderTargets(drawBuffers, renderTargets.data(),
+ depthStencil);
+ return true;
+}
+
+void StateManager11::setRenderTarget(ID3D11RenderTargetView *renderTarget,
+ ID3D11DepthStencilView *depthStencil)
+{
+ mRenderer->getDeviceContext()->OMSetRenderTargets(1, &renderTarget, depthStencil);
+}
+
+void StateManager11::setShaderResource(gl::SamplerType shaderType,
+ UINT resourceSlot,
+ ID3D11ShaderResourceView *srv)
+{
+ auto &currentSRVs = (shaderType == gl::SAMPLER_VERTEX ? mCurVertexSRVs : mCurPixelSRVs);
+
+ ASSERT(static_cast<size_t>(resourceSlot) < currentSRVs.size());
+ const SRVRecord &record = currentSRVs[resourceSlot];
+
+ if (record.srv != reinterpret_cast<uintptr_t>(srv))
+ {
+ auto deviceContext = mRenderer->getDeviceContext();
+ if (shaderType == gl::SAMPLER_VERTEX)
+ {
+ deviceContext->VSSetShaderResources(resourceSlot, 1, &srv);
+ }
+ else
+ {
+ deviceContext->PSSetShaderResources(resourceSlot, 1, &srv);
+ }
+
+ currentSRVs.update(resourceSlot, srv);
+ }
+}
+
+gl::Error StateManager11::clearTextures(gl::SamplerType samplerType,
+ size_t rangeStart,
+ size_t rangeEnd)
+{
+ if (rangeStart == rangeEnd)
+ {
+ return gl::Error(GL_NO_ERROR);
+ }
+
+ auto &currentSRVs = (samplerType == gl::SAMPLER_VERTEX ? mCurVertexSRVs : mCurPixelSRVs);
+
+ gl::Range<size_t> clearRange(rangeStart, rangeStart);
+ clearRange.extend(std::min(rangeEnd, currentSRVs.highestUsed()));
+
+ if (clearRange.empty())
+ {
+ return gl::Error(GL_NO_ERROR);
+ }
+
+ auto deviceContext = mRenderer->getDeviceContext();
+ if (samplerType == gl::SAMPLER_VERTEX)
+ {
+ deviceContext->VSSetShaderResources(static_cast<unsigned int>(rangeStart),
+ static_cast<unsigned int>(rangeEnd - rangeStart),
+ &mNullSRVs[0]);
+ }
+ else
+ {
+ deviceContext->PSSetShaderResources(static_cast<unsigned int>(rangeStart),
+ static_cast<unsigned int>(rangeEnd - rangeStart),
+ &mNullSRVs[0]);
+ }
+
+ for (size_t samplerIndex = rangeStart; samplerIndex < rangeEnd; ++samplerIndex)
+ {
+ currentSRVs.update(samplerIndex, nullptr);
+ }
+
+ return gl::Error(GL_NO_ERROR);
+}
+
+void StateManager11::unsetConflictingSRVs(gl::SamplerType samplerType,
+ uintptr_t resource,
+ const gl::ImageIndex &index)
+{
+ auto &currentSRVs = (samplerType == gl::SAMPLER_VERTEX ? mCurVertexSRVs : mCurPixelSRVs);
+
+ for (size_t resourceIndex = 0; resourceIndex < currentSRVs.size(); ++resourceIndex)
+ {
+ auto &record = currentSRVs[resourceIndex];
+
+ if (record.srv && record.resource == resource &&
+ ImageIndexConflictsWithSRV(index, record.desc))
+ {
+ setShaderResource(samplerType, static_cast<UINT>(resourceIndex), NULL);
+ }
+ }
+}
+
+void StateManager11::initialize(const gl::Caps &caps)
+{
+ mCurVertexSRVs.initialize(caps.maxVertexTextureImageUnits);
+ mCurPixelSRVs.initialize(caps.maxTextureImageUnits);
+
+ // Initialize cached NULL SRV block
+ mNullSRVs.resize(caps.maxTextureImageUnits, nullptr);
+}
+
+gl::Error StateManager11::syncFramebuffer(const gl::Framebuffer *framebuffer)
+{
+ // Get the color render buffer and serial
+ // Also extract the render target dimensions and view
+ unsigned int renderTargetWidth = 0;
+ unsigned int renderTargetHeight = 0;
+ DXGI_FORMAT renderTargetFormat = DXGI_FORMAT_UNKNOWN;
+ RenderTargetArray framebufferRTVs;
+ bool missingColorRenderTarget = true;
+
+ framebufferRTVs.fill(nullptr);
+
+ const Framebuffer11 *framebuffer11 = GetImplAs<Framebuffer11>(framebuffer);
+ const gl::AttachmentList &colorbuffers = framebuffer11->getColorAttachmentsForRender();
+
+ for (size_t colorAttachment = 0; colorAttachment < colorbuffers.size(); ++colorAttachment)
+ {
+ const gl::FramebufferAttachment *colorbuffer = colorbuffers[colorAttachment];
+
+ if (colorbuffer)
+ {
+ // the draw buffer must be either "none", "back" for the default buffer or the same
+ // index as this color (in order)
+
+ // check for zero-sized default framebuffer, which is a special case.
+ // in this case we do not wish to modify any state and just silently return false.
+ // this will not report any gl error but will cause the calling method to return.
+ const gl::Extents &size = colorbuffer->getSize();
+ if (size.width == 0 || size.height == 0)
+ {
+ return gl::Error(GL_NO_ERROR);
+ }
+
+ // Extract the render target dimensions and view
+ RenderTarget11 *renderTarget = NULL;
+ gl::Error error = colorbuffer->getRenderTarget(&renderTarget);
+ if (error.isError())
+ {
+ return error;
+ }
+ ASSERT(renderTarget);
+
+ framebufferRTVs[colorAttachment] = renderTarget->getRenderTargetView();
+ ASSERT(framebufferRTVs[colorAttachment]);
+
+ if (missingColorRenderTarget)
+ {
+ renderTargetWidth = renderTarget->getWidth();
+ renderTargetHeight = renderTarget->getHeight();
+ renderTargetFormat = renderTarget->getDXGIFormat();
+ missingColorRenderTarget = false;
+ }
+
+ // Unbind render target SRVs from the shader here to prevent D3D11 warnings.
+ if (colorbuffer->type() == GL_TEXTURE)
+ {
+ uintptr_t rtResource =
+ reinterpret_cast<uintptr_t>(GetViewResource(framebufferRTVs[colorAttachment]));
+ const gl::ImageIndex &index = colorbuffer->getTextureImageIndex();
+ // The index doesn't need to be corrected for the small compressed texture
+ // workaround
+ // because a rendertarget is never compressed.
+ unsetConflictingSRVs(gl::SAMPLER_VERTEX, rtResource, index);
+ unsetConflictingSRVs(gl::SAMPLER_PIXEL, rtResource, index);
+ }
+ }
+ }
+
+ // Get the depth stencil buffers
+ ID3D11DepthStencilView *framebufferDSV = NULL;
+ const gl::FramebufferAttachment *depthStencil = framebuffer->getDepthOrStencilbuffer();
+ if (depthStencil)
+ {
+ RenderTarget11 *depthStencilRenderTarget = NULL;
+ gl::Error error = depthStencil->getRenderTarget(&depthStencilRenderTarget);
+ if (error.isError())
+ {
+ return error;
+ }
+ ASSERT(depthStencilRenderTarget);
+
+ framebufferDSV = depthStencilRenderTarget->getDepthStencilView();
+ ASSERT(framebufferDSV);
+
+ // If there is no render buffer, the width, height and format values come from
+ // the depth stencil
+ if (missingColorRenderTarget)
+ {
+ renderTargetWidth = depthStencilRenderTarget->getWidth();
+ renderTargetHeight = depthStencilRenderTarget->getHeight();
+ }
+
+ // Unbind render target SRVs from the shader here to prevent D3D11 warnings.
+ if (depthStencil->type() == GL_TEXTURE)
+ {
+ uintptr_t depthStencilResource =
+ reinterpret_cast<uintptr_t>(GetViewResource(framebufferDSV));
+ const gl::ImageIndex &index = depthStencil->getTextureImageIndex();
+ // The index doesn't need to be corrected for the small compressed texture workaround
+ // because a rendertarget is never compressed.
+ unsetConflictingSRVs(gl::SAMPLER_VERTEX, depthStencilResource, index);
+ unsetConflictingSRVs(gl::SAMPLER_PIXEL, depthStencilResource, index);
+ }
+ }
+
+ if (setRenderTargets(framebufferRTVs, framebufferDSV))
+ {
+ setViewportBounds(renderTargetWidth, renderTargetHeight);
+ }
+
+ gl::Error error = framebuffer11->invalidateSwizzles();
+ if (error.isError())
+ {
+ return error;
+ }
+
+ return gl::Error(GL_NO_ERROR);
+}
+
+} // namespace rx
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/StateManager11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/StateManager11.h
new file mode 100644
index 0000000000..f900882d7e
--- /dev/null
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/StateManager11.h
@@ -0,0 +1,181 @@
+//
+// 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.
+//
+
+// StateManager11.h: Defines a class for caching D3D11 state
+
+#ifndef LIBANGLE_RENDERER_D3D11_STATEMANAGER11_H_
+#define LIBANGLE_RENDERER_D3D11_STATEMANAGER11_H_
+
+#include <array>
+
+#include "libANGLE/angletypes.h"
+#include "libANGLE/Data.h"
+#include "libANGLE/State.h"
+#include "libANGLE/renderer/d3d/d3d11/RenderStateCache.h"
+#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h"
+#include "libANGLE/renderer/d3d/RendererD3D.h"
+
+namespace rx
+{
+
+struct RenderTargetDesc;
+struct Renderer11DeviceCaps;
+
+struct dx_VertexConstants11
+{
+ float depthRange[4];
+ float viewAdjust[4];
+ float viewCoords[4];
+ float viewScale[4];
+};
+
+struct dx_PixelConstants11
+{
+ float depthRange[4];
+ float viewCoords[4];
+ float depthFront[4];
+ float viewScale[4];
+};
+
+class StateManager11 final : angle::NonCopyable
+{
+ public:
+ StateManager11(Renderer11 *renderer);
+ ~StateManager11();
+
+ void initialize(const gl::Caps &caps);
+ void syncState(const gl::State &state, const gl::State::DirtyBits &dirtyBits);
+
+ gl::Error setBlendState(const gl::Framebuffer *framebuffer,
+ const gl::BlendState &blendState,
+ const gl::ColorF &blendColor,
+ unsigned int sampleMask);
+
+ gl::Error setDepthStencilState(const gl::State &glState);
+
+ gl::Error setRasterizerState(const gl::RasterizerState &rasterState);
+
+ void setScissorRectangle(const gl::Rectangle &scissor, bool enabled);
+
+ void setViewport(const gl::Caps *caps, const gl::Rectangle &viewport, float zNear, float zFar);
+
+ void updatePresentPath(bool presentPathFastActive,
+ const gl::FramebufferAttachment *framebufferAttachment);
+
+ const dx_VertexConstants11 &getVertexConstants() const { return mVertexConstants; }
+ const dx_PixelConstants11 &getPixelConstants() const { return mPixelConstants; }
+
+ void updateStencilSizeIfChanged(bool depthStencilInitialized, unsigned int stencilSize);
+
+ void setShaderResource(gl::SamplerType shaderType,
+ UINT resourceSlot,
+ ID3D11ShaderResourceView *srv);
+ gl::Error clearTextures(gl::SamplerType samplerType, size_t rangeStart, size_t rangeEnd);
+
+ gl::Error syncFramebuffer(const gl::Framebuffer *framebuffer);
+
+ void invalidateRenderTarget();
+ void invalidateEverything();
+ bool setRenderTargets(const RenderTargetArray &renderTargets,
+ ID3D11DepthStencilView *depthStencil);
+ void setRenderTarget(ID3D11RenderTargetView *renderTarget,
+ ID3D11DepthStencilView *depthStencil);
+
+ private:
+ void unsetConflictingSRVs(gl::SamplerType shaderType,
+ uintptr_t resource,
+ const gl::ImageIndex &index);
+ void setViewportBounds(const int width, const int height);
+
+ Renderer11 *mRenderer;
+
+ // Blend State
+ bool mBlendStateIsDirty;
+ // TODO(dianx) temporary representation of a dirty bit. once we move enough states in,
+ // try experimenting with dirty bit instead of a bool
+ gl::BlendState mCurBlendState;
+ gl::ColorF mCurBlendColor;
+ unsigned int mCurSampleMask;
+
+ // Currently applied depth stencil state
+ bool mDepthStencilStateIsDirty;
+ gl::DepthStencilState mCurDepthStencilState;
+ int mCurStencilRef;
+ int mCurStencilBackRef;
+ unsigned int mCurStencilSize;
+ Optional<bool> mCurDisableDepth;
+ Optional<bool> mCurDisableStencil;
+
+ // Currently applied rasterizer state
+ bool mRasterizerStateIsDirty;
+ gl::RasterizerState mCurRasterState;
+
+ // Currently applied scissor rectangle state
+ bool mScissorStateIsDirty;
+ bool mCurScissorEnabled;
+ gl::Rectangle mCurScissorRect;
+
+ // Currently applied viewport state
+ bool mViewportStateIsDirty;
+ gl::Rectangle mCurViewport;
+ float mCurNear;
+ float mCurFar;
+
+ // Things needed in viewport state
+ dx_VertexConstants11 mVertexConstants;
+ dx_PixelConstants11 mPixelConstants;
+
+ // Render target variables
+ gl::Extents mViewportBounds;
+
+ // EGL_ANGLE_experimental_present_path variables
+ bool mCurPresentPathFastEnabled;
+ int mCurPresentPathFastColorBufferHeight;
+
+ // Current RenderTarget state
+ std::array<uintptr_t, gl::IMPLEMENTATION_MAX_DRAW_BUFFERS> mAppliedRTVs;
+ uintptr_t mAppliedDSV;
+
+ // Currently applied textures
+ struct SRVRecord
+ {
+ uintptr_t srv;
+ uintptr_t resource;
+ D3D11_SHADER_RESOURCE_VIEW_DESC desc;
+ };
+
+ // A cache of current SRVs that also tracks the highest 'used' (non-NULL) SRV
+ // We might want to investigate a more robust approach that is also fast when there's
+ // a large gap between used SRVs (e.g. if SRV 0 and 7 are non-NULL, this approach will
+ // waste time on SRVs 1-6.)
+ class SRVCache : angle::NonCopyable
+ {
+ public:
+ SRVCache() : mHighestUsedSRV(0) {}
+
+ void initialize(size_t size) { mCurrentSRVs.resize(size); }
+
+ size_t size() const { return mCurrentSRVs.size(); }
+ size_t highestUsed() const { return mHighestUsedSRV; }
+
+ const SRVRecord &operator[](size_t index) const { return mCurrentSRVs[index]; }
+ void clear();
+ void update(size_t resourceIndex, ID3D11ShaderResourceView *srv);
+
+ private:
+ std::vector<SRVRecord> mCurrentSRVs;
+ size_t mHighestUsedSRV;
+ };
+
+ SRVCache mCurVertexSRVs;
+ SRVCache mCurPixelSRVs;
+
+ // A block of NULL pointers, cached so we don't re-allocate every draw call
+ std::vector<ID3D11ShaderResourceView *> mNullSRVs;
+};
+
+} // namespace rx
+#endif // LIBANGLE_RENDERER_D3D11_STATEMANAGER11_H_
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/SwapChain11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/SwapChain11.cpp
index 0af2cf12c6..785a83cd77 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/SwapChain11.cpp
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/SwapChain11.cpp
@@ -7,46 +7,82 @@
// SwapChain11.cpp: Implements a back-end specific class for the D3D11 swap chain.
#include "libANGLE/renderer/d3d/d3d11/SwapChain11.h"
-#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h"
+
+#include <EGL/eglext.h>
+
+#include "libANGLE/features.h"
#include "libANGLE/renderer/d3d/d3d11/formatutils11.h"
-#include "libANGLE/renderer/d3d/d3d11/Renderer11.h"
#include "libANGLE/renderer/d3d/d3d11/NativeWindow.h"
-#include "libANGLE/features.h"
+#include "libANGLE/renderer/d3d/d3d11/Renderer11.h"
+#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h"
+#include "libANGLE/renderer/d3d/d3d11/texture_format_table.h"
+#include "third_party/trace_event/trace_event.h"
// Precompiled shaders
#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthrough2d11vs.h"
#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgba2d11ps.h"
+#ifdef ANGLE_ENABLE_KEYEDMUTEX
+#define ANGLE_RESOURCE_SHARE_TYPE D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX
+#else
+#define ANGLE_RESOURCE_SHARE_TYPE D3D11_RESOURCE_MISC_SHARED
+#endif
namespace rx
{
-SwapChain11::SwapChain11(Renderer11 *renderer, NativeWindow nativeWindow, HANDLE shareHandle,
- GLenum backBufferFormat, GLenum depthBufferFormat)
- : mRenderer(renderer),
- SwapChainD3D(nativeWindow, shareHandle, backBufferFormat, depthBufferFormat),
+namespace
+{
+bool NeedsOffscreenTexture(Renderer11 *renderer, NativeWindow nativeWindow, EGLint orientation)
+{
+ // We don't need an offscreen texture if either orientation = INVERT_Y,
+ // or present path fast is enabled and we're not rendering onto an offscreen surface.
+ return orientation != EGL_SURFACE_ORIENTATION_INVERT_Y_ANGLE &&
+ !(renderer->presentPathFastEnabled() && nativeWindow.getNativeWindow());
+}
+} // anonymous namespace
+
+SwapChain11::SwapChain11(Renderer11 *renderer,
+ NativeWindow nativeWindow,
+ HANDLE shareHandle,
+ GLenum backBufferFormat,
+ GLenum depthBufferFormat,
+ EGLint orientation)
+ : SwapChainD3D(nativeWindow, shareHandle, backBufferFormat, depthBufferFormat),
+ mRenderer(renderer),
+ mWidth(-1),
+ mHeight(-1),
+ mOrientation(orientation),
+ mAppCreatedShareHandle(mShareHandle != nullptr),
+ mSwapInterval(0),
+ mPassThroughResourcesInit(false),
+ mFirstSwap(true),
+ mSwapChain(nullptr),
+#if defined(ANGLE_ENABLE_D3D11_1)
+ mSwapChain1(nullptr),
+#endif
+ mKeyedMutex(nullptr),
+ mBackBufferTexture(nullptr),
+ mBackBufferRTView(nullptr),
+ mBackBufferSRView(nullptr),
+ mNeedsOffscreenTexture(NeedsOffscreenTexture(renderer, nativeWindow, orientation)),
+ mOffscreenTexture(nullptr),
+ mOffscreenRTView(nullptr),
+ mOffscreenSRView(nullptr),
+ mDepthStencilTexture(nullptr),
+ mDepthStencilDSView(nullptr),
+ mDepthStencilSRView(nullptr),
+ mQuadVB(nullptr),
+ mPassThroughSampler(nullptr),
+ mPassThroughIL(nullptr),
+ mPassThroughVS(nullptr),
+ mPassThroughPS(nullptr),
+ mPassThroughRS(nullptr),
mColorRenderTarget(this, renderer, false),
mDepthStencilRenderTarget(this, renderer, true)
{
- mSwapChain = NULL;
- mBackBufferTexture = NULL;
- mBackBufferRTView = NULL;
- mOffscreenTexture = NULL;
- mOffscreenRTView = NULL;
- mOffscreenSRView = NULL;
- mDepthStencilTexture = NULL;
- mDepthStencilDSView = NULL;
- mDepthStencilSRView = NULL;
- mQuadVB = NULL;
- mPassThroughSampler = NULL;
- mPassThroughIL = NULL;
- mPassThroughVS = NULL;
- mPassThroughPS = NULL;
- mWidth = -1;
- mHeight = -1;
- mSwapInterval = 0;
- mAppCreatedShareHandle = mShareHandle != NULL;
- mPassThroughResourcesInit = false;
+ // Sanity check that if present path fast is active then we're using the default orientation
+ ASSERT(!mRenderer->presentPathFastEnabled() || orientation == 0);
}
SwapChain11::~SwapChain11()
@@ -56,9 +92,14 @@ SwapChain11::~SwapChain11()
void SwapChain11::release()
{
+#if defined(ANGLE_ENABLE_D3D11_1)
+ SafeRelease(mSwapChain1);
+#endif
SafeRelease(mSwapChain);
+ SafeRelease(mKeyedMutex);
SafeRelease(mBackBufferTexture);
SafeRelease(mBackBufferRTView);
+ SafeRelease(mBackBufferSRView);
SafeRelease(mOffscreenTexture);
SafeRelease(mOffscreenRTView);
SafeRelease(mOffscreenSRView);
@@ -70,6 +111,7 @@ void SwapChain11::release()
SafeRelease(mPassThroughIL);
SafeRelease(mPassThroughVS);
SafeRelease(mPassThroughPS);
+ SafeRelease(mPassThroughRS);
if (!mAppCreatedShareHandle)
{
@@ -77,18 +119,48 @@ void SwapChain11::release()
}
}
-void SwapChain11::releaseOffscreenTexture()
+void SwapChain11::releaseOffscreenColorBuffer()
{
SafeRelease(mOffscreenTexture);
SafeRelease(mOffscreenRTView);
SafeRelease(mOffscreenSRView);
+}
+
+void SwapChain11::releaseOffscreenDepthBuffer()
+{
SafeRelease(mDepthStencilTexture);
SafeRelease(mDepthStencilDSView);
SafeRelease(mDepthStencilSRView);
}
-EGLint SwapChain11::resetOffscreenTexture(int backbufferWidth, int backbufferHeight)
+EGLint SwapChain11::resetOffscreenBuffers(int backbufferWidth, int backbufferHeight)
+{
+ if (mNeedsOffscreenTexture)
+ {
+ EGLint result = resetOffscreenColorBuffer(backbufferWidth, backbufferHeight);
+ if (result != EGL_SUCCESS)
+ {
+ return result;
+ }
+ }
+
+ EGLint result = resetOffscreenDepthBuffer(backbufferWidth, backbufferHeight);
+ if (result != EGL_SUCCESS)
+ {
+ return result;
+ }
+
+ mWidth = backbufferWidth;
+ mHeight = backbufferHeight;
+
+ return EGL_SUCCESS;
+}
+
+EGLint SwapChain11::resetOffscreenColorBuffer(int backbufferWidth, int backbufferHeight)
{
+ ASSERT(mNeedsOffscreenTexture);
+
+ TRACE_EVENT0("gpu.angle", "SwapChain11::resetOffscreenTexture");
ID3D11Device *device = mRenderer->getDevice();
ASSERT(device != NULL);
@@ -106,9 +178,9 @@ EGLint SwapChain11::resetOffscreenTexture(int backbufferWidth, int backbufferHei
const int previousWidth = mWidth;
const int previousHeight = mHeight;
- releaseOffscreenTexture();
+ releaseOffscreenColorBuffer();
- const d3d11::TextureFormat &backbufferFormatInfo = d3d11::GetTextureFormatInfo(mBackBufferFormat, mRenderer->getFeatureLevel());
+ const d3d11::TextureFormat &backbufferFormatInfo = d3d11::GetTextureFormatInfo(mOffscreenRenderTargetFormat, mRenderer->getRenderer11DeviceCaps());
// If the app passed in a share handle, open the resource
// See EGL_ANGLE_d3d_share_handle_client_buffer
@@ -164,7 +236,7 @@ EGLint SwapChain11::resetOffscreenTexture(int backbufferWidth, int backbufferHei
offscreenTextureDesc.Usage = D3D11_USAGE_DEFAULT;
offscreenTextureDesc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
offscreenTextureDesc.CPUAccessFlags = 0;
- offscreenTextureDesc.MiscFlags = useSharedResource ? D3D11_RESOURCE_MISC_SHARED : 0;
+ offscreenTextureDesc.MiscFlags = useSharedResource ? ANGLE_RESOURCE_SHARE_TYPE : 0;
HRESULT result = device->CreateTexture2D(&offscreenTextureDesc, NULL, &mOffscreenTexture);
@@ -210,6 +282,8 @@ EGLint SwapChain11::resetOffscreenTexture(int backbufferWidth, int backbufferHei
}
}
+ // This may return null if the original texture was created without a keyed mutex.
+ mKeyedMutex = d3d11::DynamicCastComObject<IDXGIKeyedMutex>(mOffscreenTexture);
D3D11_RENDER_TARGET_VIEW_DESC offscreenRTVDesc;
offscreenRTVDesc.Format = backbufferFormatInfo.rtvFormat;
@@ -230,10 +304,41 @@ EGLint SwapChain11::resetOffscreenTexture(int backbufferWidth, int backbufferHei
ASSERT(SUCCEEDED(result));
d3d11::SetDebugName(mOffscreenSRView, "Offscreen back buffer shader resource");
- const d3d11::TextureFormat &depthBufferFormatInfo = d3d11::GetTextureFormatInfo(mDepthBufferFormat, mRenderer->getFeatureLevel());
+ if (previousOffscreenTexture != nullptr)
+ {
+ D3D11_BOX sourceBox = {0};
+ sourceBox.left = 0;
+ sourceBox.right = std::min(previousWidth, backbufferWidth);
+ sourceBox.top = std::max(previousHeight - backbufferHeight, 0);
+ sourceBox.bottom = previousHeight;
+ sourceBox.front = 0;
+ sourceBox.back = 1;
+
+ ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
+ const int yoffset = std::max(backbufferHeight - previousHeight, 0);
+ deviceContext->CopySubresourceRegion(mOffscreenTexture, 0, 0, yoffset, 0,
+ previousOffscreenTexture, 0, &sourceBox);
+
+ SafeRelease(previousOffscreenTexture);
+
+ if (mSwapChain)
+ {
+ swapRect(0, 0, backbufferWidth, backbufferHeight);
+ }
+ }
+
+ return EGL_SUCCESS;
+}
+
+EGLint SwapChain11::resetOffscreenDepthBuffer(int backbufferWidth, int backbufferHeight)
+{
+ releaseOffscreenDepthBuffer();
if (mDepthBufferFormat != GL_NONE)
{
+ const d3d11::TextureFormat &depthBufferFormatInfo =
+ d3d11::GetTextureFormatInfo(mDepthBufferFormat, mRenderer->getRenderer11DeviceCaps());
+
D3D11_TEXTURE2D_DESC depthStencilTextureDesc;
depthStencilTextureDesc.Width = backbufferWidth;
depthStencilTextureDesc.Height = backbufferHeight;
@@ -253,7 +358,9 @@ EGLint SwapChain11::resetOffscreenTexture(int backbufferWidth, int backbufferHei
depthStencilTextureDesc.CPUAccessFlags = 0;
depthStencilTextureDesc.MiscFlags = 0;
- result = device->CreateTexture2D(&depthStencilTextureDesc, NULL, &mDepthStencilTexture);
+ ID3D11Device *device = mRenderer->getDevice();
+ HRESULT result =
+ device->CreateTexture2D(&depthStencilTextureDesc, NULL, &mDepthStencilTexture);
if (FAILED(result))
{
ERR("Could not create depthstencil surface for new swap chain: 0x%08X", result);
@@ -294,36 +401,12 @@ EGLint SwapChain11::resetOffscreenTexture(int backbufferWidth, int backbufferHei
}
}
- mWidth = backbufferWidth;
- mHeight = backbufferHeight;
-
- if (previousOffscreenTexture != NULL)
- {
- D3D11_BOX sourceBox = {0};
- sourceBox.left = 0;
- sourceBox.right = std::min(previousWidth, mWidth);
- sourceBox.top = std::max(previousHeight - mHeight, 0);
- sourceBox.bottom = previousHeight;
- sourceBox.front = 0;
- sourceBox.back = 1;
-
- ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
- const int yoffset = std::max(mHeight - previousHeight, 0);
- deviceContext->CopySubresourceRegion(mOffscreenTexture, 0, 0, yoffset, 0, previousOffscreenTexture, 0, &sourceBox);
-
- SafeRelease(previousOffscreenTexture);
-
- if (mSwapChain)
- {
- swapRect(0, 0, mWidth, mHeight);
- }
- }
-
return EGL_SUCCESS;
}
EGLint SwapChain11::resize(EGLint backbufferWidth, EGLint backbufferHeight)
{
+ TRACE_EVENT0("gpu.angle", "SwapChain11::resize");
ID3D11Device *device = mRenderer->getDevice();
if (device == NULL)
@@ -337,17 +420,30 @@ EGLint SwapChain11::resize(EGLint backbufferWidth, EGLint backbufferHeight)
return EGL_SUCCESS;
}
+ // Don't resize unnecessarily
+ if (mWidth == backbufferWidth && mHeight == backbufferHeight)
+ {
+ return EGL_SUCCESS;
+ }
+
// Can only call resize if we have already created our swap buffer and resources
- ASSERT(mSwapChain && mBackBufferTexture && mBackBufferRTView);
+ ASSERT(mSwapChain && mBackBufferTexture && mBackBufferRTView && mBackBufferSRView);
SafeRelease(mBackBufferTexture);
SafeRelease(mBackBufferRTView);
+ SafeRelease(mBackBufferSRView);
// Resize swap chain
DXGI_SWAP_CHAIN_DESC desc;
- mSwapChain->GetDesc(&desc);
- const d3d11::TextureFormat &backbufferFormatInfo = d3d11::GetTextureFormatInfo(mBackBufferFormat, mRenderer->getFeatureLevel());
- HRESULT result = mSwapChain->ResizeBuffers(desc.BufferCount, backbufferWidth, backbufferHeight, backbufferFormatInfo.texFormat, 0);
+ HRESULT result = mSwapChain->GetDesc(&desc);
+ if (FAILED(result))
+ {
+ ERR("Error reading swap chain description: 0x%08X", result);
+ release();
+ return EGL_BAD_ALLOC;
+ }
+
+ result = mSwapChain->ResizeBuffers(desc.BufferCount, backbufferWidth, backbufferHeight, getSwapChainNativeFormat(), 0);
if (FAILED(result))
{
@@ -369,20 +465,50 @@ EGLint SwapChain11::resize(EGLint backbufferWidth, EGLint backbufferHeight)
if (SUCCEEDED(result))
{
d3d11::SetDebugName(mBackBufferTexture, "Back buffer texture");
- }
+ result = device->CreateRenderTargetView(mBackBufferTexture, NULL, &mBackBufferRTView);
+ ASSERT(SUCCEEDED(result));
+ if (SUCCEEDED(result))
+ {
+ d3d11::SetDebugName(mBackBufferRTView, "Back buffer render target");
+ }
- result = device->CreateRenderTargetView(mBackBufferTexture, NULL, &mBackBufferRTView);
- ASSERT(SUCCEEDED(result));
- if (SUCCEEDED(result))
- {
- d3d11::SetDebugName(mBackBufferRTView, "Back buffer render target");
+ result = device->CreateShaderResourceView(mBackBufferTexture, nullptr, &mBackBufferSRView);
+ ASSERT(SUCCEEDED(result));
+ if (SUCCEEDED(result))
+ {
+ d3d11::SetDebugName(mBackBufferSRView, "Back buffer shader resource");
+ }
}
- return resetOffscreenTexture(backbufferWidth, backbufferHeight);
+ mFirstSwap = true;
+
+ return resetOffscreenBuffers(backbufferWidth, backbufferHeight);
+}
+
+DXGI_FORMAT SwapChain11::getSwapChainNativeFormat() const
+{
+ // Return a render target format for offscreen rendering is supported by IDXGISwapChain.
+ // MSDN https://msdn.microsoft.com/en-us/library/windows/desktop/bb173064(v=vs.85).aspx
+ return (mOffscreenRenderTargetFormat == GL_BGRA8_EXT) ? DXGI_FORMAT_B8G8R8A8_UNORM : DXGI_FORMAT_R8G8B8A8_UNORM;
}
EGLint SwapChain11::reset(int backbufferWidth, int backbufferHeight, EGLint swapInterval)
{
+ mSwapInterval = static_cast<unsigned int>(swapInterval);
+ if (mSwapInterval > 4)
+ {
+ // IDXGISwapChain::Present documentation states that valid sync intervals are in the [0,4]
+ // range
+ return EGL_BAD_PARAMETER;
+ }
+
+ // If the swap chain already exists, just resize
+ if (mSwapChain != nullptr)
+ {
+ return resize(backbufferWidth, backbufferHeight);
+ }
+
+ TRACE_EVENT0("gpu.angle", "SwapChain11::reset");
ID3D11Device *device = mRenderer->getDevice();
if (device == NULL)
@@ -392,30 +518,24 @@ EGLint SwapChain11::reset(int backbufferWidth, int backbufferHeight, EGLint swap
// Release specific resources to free up memory for the new render target, while the
// old render target still exists for the purpose of preserving its contents.
+#if defined(ANGLE_ENABLE_D3D11_1)
+ SafeRelease(mSwapChain1);
+#endif
SafeRelease(mSwapChain);
SafeRelease(mBackBufferTexture);
SafeRelease(mBackBufferRTView);
- mSwapInterval = static_cast<unsigned int>(swapInterval);
- if (mSwapInterval > 4)
- {
- // IDXGISwapChain::Present documentation states that valid sync intervals are in the [0,4] range
- return EGL_BAD_PARAMETER;
- }
-
// EGL allows creating a surface with 0x0 dimension, however, DXGI does not like 0x0 swapchains
if (backbufferWidth < 1 || backbufferHeight < 1)
{
- releaseOffscreenTexture();
+ releaseOffscreenColorBuffer();
return EGL_SUCCESS;
}
if (mNativeWindow.getNativeWindow())
{
- const d3d11::TextureFormat &backbufferFormatInfo = d3d11::GetTextureFormatInfo(mBackBufferFormat, mRenderer->getFeatureLevel());
-
HRESULT result = mNativeWindow.createSwapChain(device, mRenderer->getDxgiFactory(),
- backbufferFormatInfo.texFormat,
+ getSwapChainNativeFormat(),
backbufferWidth, backbufferHeight, &mSwapChain);
if (FAILED(result))
@@ -433,6 +553,13 @@ EGLint SwapChain11::reset(int backbufferWidth, int backbufferHeight, EGLint swap
}
}
+ if (mRenderer->getRenderer11DeviceCaps().supportsDXGI1_2)
+ {
+#if defined(ANGLE_ENABLE_D3D11_1)
+ mSwapChain1 = d3d11::DynamicCastComObject<IDXGISwapChain1>(mSwapChain);
+#endif
+ }
+
result = mSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&mBackBufferTexture);
ASSERT(SUCCEEDED(result));
d3d11::SetDebugName(mBackBufferTexture, "Back buffer texture");
@@ -440,20 +567,25 @@ EGLint SwapChain11::reset(int backbufferWidth, int backbufferHeight, EGLint swap
result = device->CreateRenderTargetView(mBackBufferTexture, NULL, &mBackBufferRTView);
ASSERT(SUCCEEDED(result));
d3d11::SetDebugName(mBackBufferRTView, "Back buffer render target");
- }
- // If we are resizing the swap chain, we don't wish to recreate all the static resources
- if (!mPassThroughResourcesInit)
- {
- mPassThroughResourcesInit = true;
- initPassThroughResources();
+ result = device->CreateShaderResourceView(mBackBufferTexture, nullptr, &mBackBufferSRView);
+ ASSERT(SUCCEEDED(result));
+ d3d11::SetDebugName(mBackBufferSRView, "Back buffer shader resource view");
}
- return resetOffscreenTexture(backbufferWidth, backbufferHeight);
+ mFirstSwap = true;
+
+ return resetOffscreenBuffers(backbufferWidth, backbufferHeight);
}
void SwapChain11::initPassThroughResources()
{
+ if (mPassThroughResourcesInit)
+ {
+ return;
+ }
+
+ TRACE_EVENT0("gpu.angle", "SwapChain11::initPassThroughResources");
ID3D11Device *device = mRenderer->getDevice();
ASSERT(device != NULL);
@@ -510,17 +642,58 @@ void SwapChain11::initPassThroughResources()
result = device->CreatePixelShader(g_PS_PassthroughRGBA2D, sizeof(g_PS_PassthroughRGBA2D), NULL, &mPassThroughPS);
ASSERT(SUCCEEDED(result));
d3d11::SetDebugName(mPassThroughPS, "Swap chain pass through pixel shader");
+
+ // Use the default rasterizer state but without culling
+ D3D11_RASTERIZER_DESC rasterizerDesc;
+ rasterizerDesc.FillMode = D3D11_FILL_SOLID;
+ rasterizerDesc.CullMode = D3D11_CULL_NONE;
+ rasterizerDesc.FrontCounterClockwise = FALSE;
+ rasterizerDesc.DepthBias = 0;
+ rasterizerDesc.SlopeScaledDepthBias = 0.0f;
+ rasterizerDesc.DepthBiasClamp = 0.0f;
+ rasterizerDesc.DepthClipEnable = TRUE;
+ rasterizerDesc.ScissorEnable = FALSE;
+ rasterizerDesc.MultisampleEnable = FALSE;
+ rasterizerDesc.AntialiasedLineEnable = FALSE;
+ result = device->CreateRasterizerState(&rasterizerDesc, &mPassThroughRS);
+ ASSERT(SUCCEEDED(result));
+ d3d11::SetDebugName(mPassThroughRS, "Swap chain pass through rasterizer state");
+
+ mPassThroughResourcesInit = true;
}
// parameters should be validated/clamped by caller
EGLint SwapChain11::swapRect(EGLint x, EGLint y, EGLint width, EGLint height)
{
+ if (mNeedsOffscreenTexture)
+ {
+ EGLint result = copyOffscreenToBackbuffer(x, y, width, height);
+ if (result != EGL_SUCCESS)
+ {
+ return result;
+ }
+ }
+
+ EGLint result = present(x, y, width, height);
+ if (result != EGL_SUCCESS)
+ {
+ return result;
+ }
+
+ mRenderer->onSwap();
+
+ return EGL_SUCCESS;
+}
+
+EGLint SwapChain11::copyOffscreenToBackbuffer(EGLint x, EGLint y, EGLint width, EGLint height)
+{
if (!mSwapChain)
{
return EGL_SUCCESS;
}
- ID3D11Device *device = mRenderer->getDevice();
+ initPassThroughResources();
+
ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
// Set vertices
@@ -544,6 +717,16 @@ EGLint SwapChain11::swapRect(EGLint x, EGLint y, EGLint width, EGLint height)
float u2 = (x + width) / float(mWidth);
float v2 = (y + height) / float(mHeight);
+ // Invert the quad vertices depending on the surface orientation.
+ if ((mOrientation & EGL_SURFACE_ORIENTATION_INVERT_X_ANGLE) != 0)
+ {
+ std::swap(x1, x2);
+ }
+ if ((mOrientation & EGL_SURFACE_ORIENTATION_INVERT_Y_ANGLE) != 0)
+ {
+ std::swap(y1, y2);
+ }
+
d3d11::SetPositionTexCoordVertex(&vertices[0], x1, y1, u1, v1);
d3d11::SetPositionTexCoordVertex(&vertices[1], x1, y2, u1, v2);
d3d11::SetPositionTexCoordVertex(&vertices[2], x2, y1, u2, v1);
@@ -561,7 +744,7 @@ EGLint SwapChain11::swapRect(EGLint x, EGLint y, EGLint width, EGLint height)
static const float blendFactor[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
deviceContext->OMSetBlendState(NULL, blendFactor, 0xFFFFFFF);
- deviceContext->RSSetState(NULL);
+ deviceContext->RSSetState(mPassThroughRS);
// Apply shaders
deviceContext->IASetInputLayout(mPassThroughIL);
@@ -577,30 +760,79 @@ EGLint SwapChain11::swapRect(EGLint x, EGLint y, EGLint width, EGLint height)
D3D11_VIEWPORT viewport;
viewport.TopLeftX = 0;
viewport.TopLeftY = 0;
- viewport.Width = mWidth;
- viewport.Height = mHeight;
+ viewport.Width = static_cast<FLOAT>(mWidth);
+ viewport.Height = static_cast<FLOAT>(mHeight);
viewport.MinDepth = 0.0f;
viewport.MaxDepth = 1.0f;
deviceContext->RSSetViewports(1, &viewport);
// Apply textures
- mRenderer->setShaderResource(gl::SAMPLER_PIXEL, 0, mOffscreenSRView);
+ auto stateManager = mRenderer->getStateManager();
+ stateManager->setShaderResource(gl::SAMPLER_PIXEL, 0, mOffscreenSRView);
deviceContext->PSSetSamplers(0, 1, &mPassThroughSampler);
// Draw
deviceContext->Draw(4, 0);
+ // Rendering to the swapchain is now complete. Now we can call Present().
+ // Before that, we perform any cleanup on the D3D device. We do this before Present() to make sure the
+ // cleanup is caught under the current eglSwapBuffers() PIX/Graphics Diagnostics call rather than the next one.
+ stateManager->setShaderResource(gl::SAMPLER_PIXEL, 0, NULL);
+
+ mRenderer->unapplyRenderTargets();
+ mRenderer->markAllStateDirty();
+
+ return EGL_SUCCESS;
+}
+
+EGLint SwapChain11::present(EGLint x, EGLint y, EGLint width, EGLint height)
+{
+ if (!mSwapChain)
+ {
+ return EGL_SUCCESS;
+ }
+
+ UINT swapInterval = mSwapInterval;
#if ANGLE_VSYNC == ANGLE_DISABLED
- result = mSwapChain->Present(0, 0);
-#else
- result = mSwapChain->Present(mSwapInterval, 0);
+ swapInterval = 0;
#endif
+ HRESULT result = S_OK;
+
+#if defined(ANGLE_ENABLE_D3D11_1)
+ // Use IDXGISwapChain1::Present1 with a dirty rect if DXGI 1.2 is available.
+ if (mSwapChain1 != nullptr)
+ {
+ if (mFirstSwap)
+ {
+ // Can't swap with a dirty rect if this swap chain has never swapped before
+ DXGI_PRESENT_PARAMETERS params = {0, nullptr, nullptr, nullptr};
+ result = mSwapChain1->Present1(swapInterval, 0, &params);
+ }
+ else
+ {
+ RECT rect = {static_cast<LONG>(x), static_cast<LONG>(mHeight - y - height),
+ static_cast<LONG>(x + width), static_cast<LONG>(mHeight - y)};
+ DXGI_PRESENT_PARAMETERS params = {1, &rect, nullptr, nullptr};
+ result = mSwapChain1->Present1(swapInterval, 0, &params);
+ }
+ }
+ else
+#endif
+ {
+ result = mSwapChain->Present(swapInterval, 0);
+ }
+
+ mFirstSwap = false;
+
+ // Some swapping mechanisms such as DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL unbind the current render
+ // target. Mark it dirty.
+ mRenderer->getStateManager()->invalidateRenderTarget();
+
if (result == DXGI_ERROR_DEVICE_REMOVED)
{
- HRESULT removedReason = device->GetDeviceRemovedReason();
- UNUSED_TRACE_VARIABLE(removedReason);
- ERR("Present failed: the D3D11 device was removed: 0x%08X", removedReason);
+ ERR("Present failed: the D3D11 device was removed: 0x%08X",
+ mRenderer->getDevice()->GetDeviceRemovedReason());
return EGL_CONTEXT_LOST;
}
else if (result == DXGI_ERROR_DEVICE_RESET)
@@ -613,28 +845,24 @@ EGLint SwapChain11::swapRect(EGLint x, EGLint y, EGLint width, EGLint height)
ERR("Present failed with error code 0x%08X", result);
}
- // Unbind
- mRenderer->setShaderResource(gl::SAMPLER_PIXEL, 0, NULL);
-
- mRenderer->unapplyRenderTargets();
- mRenderer->markAllStateDirty();
+ mNativeWindow.commitChange();
return EGL_SUCCESS;
}
ID3D11Texture2D *SwapChain11::getOffscreenTexture()
{
- return mOffscreenTexture;
+ return mNeedsOffscreenTexture ? mOffscreenTexture : mBackBufferTexture;
}
ID3D11RenderTargetView *SwapChain11::getRenderTarget()
{
- return mOffscreenRTView;
+ return mNeedsOffscreenTexture ? mOffscreenRTView : mBackBufferRTView;
}
ID3D11ShaderResourceView *SwapChain11::getRenderTargetShaderResource()
{
- return mOffscreenSRView;
+ return mNeedsOffscreenTexture ? mOffscreenSRView : mBackBufferSRView;
}
ID3D11DepthStencilView *SwapChain11::getDepthStencil()
@@ -652,12 +880,6 @@ ID3D11Texture2D *SwapChain11::getDepthStencilTexture()
return mDepthStencilTexture;
}
-SwapChain11 *SwapChain11::makeSwapChain11(SwapChainD3D *swapChain)
-{
- ASSERT(HAS_DYNAMIC_TYPE(SwapChain11*, swapChain));
- return static_cast<SwapChain11*>(swapChain);
-}
-
void SwapChain11::recreate()
{
// possibly should use this method instead of reset
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/SwapChain11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/SwapChain11.h
index 48c808a261..adcd07adb0 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/SwapChain11.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/SwapChain11.h
@@ -20,8 +20,12 @@ class Renderer11;
class SwapChain11 : public SwapChainD3D
{
public:
- SwapChain11(Renderer11 *renderer, NativeWindow nativeWindow, HANDLE shareHandle,
- GLenum backBufferFormat, GLenum depthBufferFormat);
+ SwapChain11(Renderer11 *renderer,
+ NativeWindow nativeWindow,
+ HANDLE shareHandle,
+ GLenum backBufferFormat,
+ GLenum depthBufferFormat,
+ EGLint orientation);
virtual ~SwapChain11();
EGLint resize(EGLint backbufferWidth, EGLint backbufferHeight);
@@ -42,29 +46,45 @@ class SwapChain11 : public SwapChainD3D
EGLint getWidth() const { return mWidth; }
EGLint getHeight() const { return mHeight; }
+ void *getKeyedMutex() override { return mKeyedMutex; }
virtual void *getDevice();
- static SwapChain11 *makeSwapChain11(SwapChainD3D *swapChain);
-
private:
void release();
void initPassThroughResources();
- void releaseOffscreenTexture();
- EGLint resetOffscreenTexture(int backbufferWidth, int backbufferHeight);
+
+ void releaseOffscreenColorBuffer();
+ void releaseOffscreenDepthBuffer();
+ EGLint resetOffscreenBuffers(int backbufferWidth, int backbufferHeight);
+ EGLint resetOffscreenColorBuffer(int backbufferWidth, int backbufferHeight);
+ EGLint resetOffscreenDepthBuffer(int backbufferWidth, int backbufferHeight);
+
+ DXGI_FORMAT getSwapChainNativeFormat() const;
+
+ EGLint copyOffscreenToBackbuffer(EGLint x, EGLint y, EGLint width, EGLint height);
+ EGLint present(EGLint x, EGLint y, EGLint width, EGLint height);
Renderer11 *mRenderer;
- EGLint mHeight;
EGLint mWidth;
+ EGLint mHeight;
+ const EGLint mOrientation;
bool mAppCreatedShareHandle;
unsigned int mSwapInterval;
bool mPassThroughResourcesInit;
+ bool mFirstSwap;
DXGISwapChain *mSwapChain;
+#if defined(ANGLE_ENABLE_D3D11_1)
+ IDXGISwapChain1 *mSwapChain1;
+#endif
+ IDXGIKeyedMutex *mKeyedMutex;
ID3D11Texture2D *mBackBufferTexture;
ID3D11RenderTargetView *mBackBufferRTView;
+ ID3D11ShaderResourceView *mBackBufferSRView;
+ const bool mNeedsOffscreenTexture;
ID3D11Texture2D *mOffscreenTexture;
ID3D11RenderTargetView *mOffscreenRTView;
ID3D11ShaderResourceView *mOffscreenSRView;
@@ -78,6 +98,7 @@ class SwapChain11 : public SwapChainD3D
ID3D11InputLayout *mPassThroughIL;
ID3D11VertexShader *mPassThroughVS;
ID3D11PixelShader *mPassThroughPS;
+ ID3D11RasterizerState *mPassThroughRS;
SurfaceRenderTarget11 mColorRenderTarget;
SurfaceRenderTarget11 mDepthStencilRenderTarget;
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/TextureStorage11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/TextureStorage11.cpp
index 103e90fed3..11b9f76464 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/TextureStorage11.cpp
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/TextureStorage11.cpp
@@ -13,22 +13,27 @@
#include "common/MemoryBuffer.h"
#include "common/utilities.h"
-#include "libANGLE/ImageIndex.h"
#include "libANGLE/formatutils.h"
-#include "libANGLE/renderer/d3d/TextureD3D.h"
+#include "libANGLE/ImageIndex.h"
#include "libANGLE/renderer/d3d/d3d11/Blit11.h"
+#include "libANGLE/renderer/d3d/d3d11/formatutils11.h"
#include "libANGLE/renderer/d3d/d3d11/Image11.h"
-#include "libANGLE/renderer/d3d/d3d11/RenderTarget11.h"
#include "libANGLE/renderer/d3d/d3d11/Renderer11.h"
-#include "libANGLE/renderer/d3d/d3d11/SwapChain11.h"
-#include "libANGLE/renderer/d3d/d3d11/formatutils11.h"
#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h"
+#include "libANGLE/renderer/d3d/d3d11/RenderTarget11.h"
+#include "libANGLE/renderer/d3d/d3d11/SwapChain11.h"
+#include "libANGLE/renderer/d3d/d3d11/texture_format_table.h"
+#include "libANGLE/renderer/d3d/EGLImageD3D.h"
+#include "libANGLE/renderer/d3d/TextureD3D.h"
namespace rx
{
TextureStorage11::SwizzleCacheValue::SwizzleCacheValue()
- : swizzleRed(GL_NONE), swizzleGreen(GL_NONE), swizzleBlue(GL_NONE), swizzleAlpha(GL_NONE)
+ : swizzleRed(GL_INVALID_INDEX),
+ swizzleGreen(GL_INVALID_INDEX),
+ swizzleBlue(GL_INVALID_INDEX),
+ swizzleAlpha(GL_INVALID_INDEX)
{
}
@@ -60,8 +65,8 @@ bool TextureStorage11::SRVKey::operator<(const SRVKey &rhs) const
return std::tie(baseLevel, mipLevels, swizzle) < std::tie(rhs.baseLevel, rhs.mipLevels, rhs.swizzle);
}
-TextureStorage11::TextureStorage11(Renderer11 *renderer, UINT bindFlags)
- : mBindFlags(bindFlags),
+TextureStorage11::TextureStorage11(Renderer11 *renderer, UINT bindFlags, UINT miscFlags)
+ : mRenderer(renderer),
mTopLevel(0),
mMipLevels(0),
mInternalFormat(GL_NONE),
@@ -71,13 +76,13 @@ TextureStorage11::TextureStorage11(Renderer11 *renderer, UINT bindFlags)
mDepthStencilFormat(DXGI_FORMAT_UNKNOWN),
mTextureWidth(0),
mTextureHeight(0),
- mTextureDepth(0)
+ mTextureDepth(0),
+ mBindFlags(bindFlags),
+ mMiscFlags(miscFlags)
{
- mRenderer = Renderer11::makeRenderer11(renderer);
-
for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
{
- mLevelSRVs[i] = NULL;
+ mLevelSRVs[i] = nullptr;
}
}
@@ -95,17 +100,11 @@ TextureStorage11::~TextureStorage11()
mSrvCache.clear();
}
-TextureStorage11 *TextureStorage11::makeTextureStorage11(TextureStorage *storage)
-{
- ASSERT(HAS_DYNAMIC_TYPE(TextureStorage11*, storage));
- return static_cast<TextureStorage11*>(storage);
-}
-
-DWORD TextureStorage11::GetTextureBindFlags(GLenum internalFormat, D3D_FEATURE_LEVEL featureLevel, bool renderTarget)
+DWORD TextureStorage11::GetTextureBindFlags(GLenum internalFormat, const Renderer11DeviceCaps &renderer11DeviceCaps, bool renderTarget)
{
UINT bindFlags = 0;
- const d3d11::TextureFormat &formatInfo = d3d11::GetTextureFormatInfo(internalFormat, featureLevel);
+ const d3d11::TextureFormat &formatInfo = d3d11::GetTextureFormatInfo(internalFormat, renderer11DeviceCaps);
if (formatInfo.srvFormat != DXGI_FORMAT_UNKNOWN)
{
bindFlags |= D3D11_BIND_SHADER_RESOURCE;
@@ -122,11 +121,34 @@ DWORD TextureStorage11::GetTextureBindFlags(GLenum internalFormat, D3D_FEATURE_L
return bindFlags;
}
+DWORD TextureStorage11::GetTextureMiscFlags(GLenum internalFormat, const Renderer11DeviceCaps &renderer11DeviceCaps, bool renderTarget, int levels)
+{
+ UINT miscFlags = 0;
+
+ const d3d11::TextureFormat &formatInfo = d3d11::GetTextureFormatInfo(internalFormat, renderer11DeviceCaps);
+ if (renderTarget && levels > 1)
+ {
+ const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(formatInfo.texFormat);
+
+ if (dxgiFormatInfo.nativeMipmapSupport(renderer11DeviceCaps.featureLevel))
+ {
+ miscFlags |= D3D11_RESOURCE_MISC_GENERATE_MIPS;
+ }
+ }
+
+ return miscFlags;
+}
+
UINT TextureStorage11::getBindFlags() const
{
return mBindFlags;
}
+UINT TextureStorage11::getMiscFlags() const
+{
+ return mMiscFlags;
+}
+
int TextureStorage11::getTopLevel() const
{
return mTopLevel;
@@ -142,6 +164,11 @@ bool TextureStorage11::isManaged() const
return false;
}
+bool TextureStorage11::supportsNativeMipmapFunction() const
+{
+ return (mMiscFlags & D3D11_RESOURCE_MISC_GENERATE_MIPS) != 0;
+}
+
int TextureStorage11::getLevelCount() const
{
return mMipLevels - mTopLevel;
@@ -171,16 +198,17 @@ UINT TextureStorage11::getSubresourceIndex(const gl::ImageIndex &index) const
return subresource;
}
-gl::Error TextureStorage11::getSRV(const gl::SamplerState &samplerState, ID3D11ShaderResourceView **outSRV)
+gl::Error TextureStorage11::getSRV(const gl::TextureState &textureState,
+ ID3D11ShaderResourceView **outSRV)
{
- bool swizzleRequired = samplerState.swizzleRequired();
- bool mipmapping = gl::IsMipmapFiltered(samplerState);
- unsigned int mipLevels = mipmapping ? (samplerState.maxLevel - samplerState.baseLevel + 1) : 1;
+ bool swizzleRequired = textureState.swizzleRequired();
+ bool mipmapping = gl::IsMipmapFiltered(textureState.samplerState);
+ unsigned int mipLevels = mipmapping ? (textureState.maxLevel - textureState.baseLevel + 1) : 1;
- // Make sure there's 'mipLevels' mipmap levels below the base level (offset by the top level, which corresponds to GL level 0)
- mipLevels = std::min(mipLevels, mMipLevels - mTopLevel - samplerState.baseLevel);
+ // Make sure there's 'mipLevels' mipmap levels below the base level (offset by the top level, which corresponds to GL level 0)
+ mipLevels = std::min(mipLevels, mMipLevels - mTopLevel - textureState.baseLevel);
- if (mRenderer->getFeatureLevel() <= D3D_FEATURE_LEVEL_9_3)
+ if (mRenderer->getRenderer11DeviceCaps().featureLevel <= D3D_FEATURE_LEVEL_9_3)
{
ASSERT(!swizzleRequired);
ASSERT(mipLevels == 1 || mipLevels == mMipLevels);
@@ -198,47 +226,47 @@ gl::Error TextureStorage11::getSRV(const gl::SamplerState &samplerState, ID3D11S
if (swizzleRequired)
{
- verifySwizzleExists(samplerState.swizzleRed, samplerState.swizzleGreen, samplerState.swizzleBlue, samplerState.swizzleAlpha);
+ verifySwizzleExists(textureState.swizzleRed, textureState.swizzleGreen,
+ textureState.swizzleBlue, textureState.swizzleAlpha);
}
- SRVKey key(samplerState.baseLevel, mipLevels, swizzleRequired);
- SRVCache::const_iterator iter = mSrvCache.find(key);
+ SRVKey key(textureState.baseLevel, mipLevels, swizzleRequired);
+ auto iter = mSrvCache.find(key);
if (iter != mSrvCache.end())
{
*outSRV = iter->second;
+ return gl::Error(GL_NO_ERROR);
}
- else
+
+ ID3D11Resource *texture = nullptr;
+ if (swizzleRequired)
{
- ID3D11Resource *texture = NULL;
- if (swizzleRequired)
- {
- gl::Error error = getSwizzleTexture(&texture);
- if (error.isError())
- {
- return error;
- }
- }
- else
+ gl::Error error = getSwizzleTexture(&texture);
+ if (error.isError())
{
- gl::Error error = getResource(&texture);
- if (error.isError())
- {
- return error;
- }
+ return error;
}
-
- ID3D11ShaderResourceView *srv = NULL;
- DXGI_FORMAT format = (swizzleRequired ? mSwizzleShaderResourceFormat : mShaderResourceFormat);
- gl::Error error = createSRV(samplerState.baseLevel, mipLevels, format, texture, &srv);
+ }
+ else
+ {
+ gl::Error error = getResource(&texture);
if (error.isError())
{
return error;
}
+ }
- mSrvCache.insert(std::make_pair(key, srv));
- *outSRV = srv;
+ ID3D11ShaderResourceView *srv = nullptr;
+ DXGI_FORMAT format = (swizzleRequired ? mSwizzleShaderResourceFormat : mShaderResourceFormat);
+ gl::Error error = createSRV(textureState.baseLevel, mipLevels, format, texture, &srv);
+ if (error.isError())
+ {
+ return error;
}
+ mSrvCache.insert(std::make_pair(key, srv));
+ *outSRV = srv;
+
return gl::Error(GL_NO_ERROR);
}
@@ -267,6 +295,56 @@ gl::Error TextureStorage11::getSRVLevel(int mipLevel, ID3D11ShaderResourceView *
return gl::Error(GL_NO_ERROR);
}
+gl::Error TextureStorage11::getSRVLevels(GLint baseLevel, GLint maxLevel, ID3D11ShaderResourceView **outSRV)
+{
+ unsigned int mipLevels = maxLevel - baseLevel + 1;
+
+ // Make sure there's 'mipLevels' mipmap levels below the base level (offset by the top level, which corresponds to GL level 0)
+ mipLevels = std::min(mipLevels, mMipLevels - mTopLevel - baseLevel);
+
+ if (mRenderer->getRenderer11DeviceCaps().featureLevel <= D3D_FEATURE_LEVEL_9_3)
+ {
+ ASSERT(mipLevels == 1 || mipLevels == mMipLevels);
+ }
+
+ if (mRenderer->getWorkarounds().zeroMaxLodWorkaround)
+ {
+ // We must ensure that the level zero texture is in sync with mipped texture.
+ gl::Error error = useLevelZeroWorkaroundTexture(mipLevels == 1);
+ if (error.isError())
+ {
+ return error;
+ }
+ }
+
+ SRVKey key(baseLevel, mipLevels, false);
+ auto iter = mSrvCache.find(key);
+ if (iter != mSrvCache.end())
+ {
+ *outSRV = iter->second;
+ return gl::Error(GL_NO_ERROR);
+ }
+
+ ID3D11Resource *texture = nullptr;
+ gl::Error error = getResource(&texture);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ ID3D11ShaderResourceView *srv = nullptr;
+ error = createSRV(baseLevel, mipLevels, mShaderResourceFormat, texture, &srv);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ mSrvCache[key] = srv;
+ *outSRV = srv;
+
+ return gl::Error(GL_NO_ERROR);
+}
+
gl::Error TextureStorage11::generateSwizzles(GLenum swizzleRed, GLenum swizzleGreen, GLenum swizzleBlue, GLenum swizzleAlpha)
{
SwizzleCacheValue swizzleTarget(swizzleRed, swizzleGreen, swizzleBlue, swizzleAlpha);
@@ -427,7 +505,7 @@ gl::Error TextureStorage11::copySubresourceLevel(ID3D11Resource* dstTexture, uns
// D3D11 can't perform partial CopySubresourceRegion on depth/stencil textures, so pSrcBox should be NULL.
D3D11_BOX srcBox;
D3D11_BOX *pSrcBox = NULL;
- if (mRenderer->getFeatureLevel() <= D3D_FEATURE_LEVEL_9_3)
+ if (mRenderer->getRenderer11DeviceCaps().featureLevel <= D3D_FEATURE_LEVEL_9_3)
{
// However, D3D10Level9 doesn't always perform CopySubresourceRegion correctly unless the source box
// is specified. This is okay, since we don't perform CopySubresourceRegion on depth/stencil
@@ -469,8 +547,8 @@ gl::Error TextureStorage11::generateMipmap(const gl::ImageIndex &sourceIndex, co
return error;
}
- ID3D11ShaderResourceView *sourceSRV = RenderTarget11::makeRenderTarget11(source)->getShaderResourceView();
- ID3D11RenderTargetView *destRTV = RenderTarget11::makeRenderTarget11(dest)->getRenderTargetView();
+ ID3D11ShaderResourceView *sourceSRV = GetAs<RenderTarget11>(source)->getShaderResourceView();
+ ID3D11RenderTargetView *destRTV = GetAs<RenderTarget11>(dest)->getRenderTargetView();
gl::Box sourceArea(0, 0, 0, source->getWidth(), source->getHeight(), source->getDepth());
gl::Extents sourceSize(source->getWidth(), source->getHeight(), source->getDepth());
@@ -479,8 +557,9 @@ gl::Error TextureStorage11::generateMipmap(const gl::ImageIndex &sourceIndex, co
gl::Extents destSize(dest->getWidth(), dest->getHeight(), dest->getDepth());
Blit11 *blitter = mRenderer->getBlitter();
- return blitter->copyTexture(sourceSRV, sourceArea, sourceSize, destRTV, destArea, destSize, NULL,
- gl::GetInternalFormatInfo(source->getInternalFormat()).format, GL_LINEAR);
+ return blitter->copyTexture(sourceSRV, sourceArea, sourceSize, destRTV, destArea, destSize,
+ NULL, gl::GetInternalFormatInfo(source->getInternalFormat()).format,
+ GL_LINEAR, false);
}
void TextureStorage11::verifySwizzleExists(GLenum swizzleRed, GLenum swizzleGreen, GLenum swizzleBlue, GLenum swizzleAlpha)
@@ -492,6 +571,30 @@ void TextureStorage11::verifySwizzleExists(GLenum swizzleRed, GLenum swizzleGree
}
}
+void TextureStorage11::clearSRVCache()
+{
+ invalidateSwizzleCache();
+
+ auto iter = mSrvCache.begin();
+ while (iter != mSrvCache.end())
+ {
+ if (!iter->first.swizzle)
+ {
+ SafeRelease(iter->second);
+ iter = mSrvCache.erase(iter);
+ }
+ else
+ {
+ iter++;
+ }
+ }
+
+ for (size_t level = 0; level < ArraySize(mLevelSRVs); level++)
+ {
+ SafeRelease(mLevelSRVs[level]);
+ }
+}
+
gl::Error TextureStorage11::copyToStorage(TextureStorage *destStorage)
{
ASSERT(destStorage);
@@ -503,7 +606,7 @@ gl::Error TextureStorage11::copyToStorage(TextureStorage *destStorage)
return error;
}
- TextureStorage11 *dest11 = TextureStorage11::makeTextureStorage11(destStorage);
+ TextureStorage11 *dest11 = GetAs<TextureStorage11>(destStorage);
ID3D11Resource *destResource = NULL;
error = dest11->getResource(&destResource);
if (error.isError())
@@ -550,29 +653,43 @@ gl::Error TextureStorage11::setData(const gl::ImageIndex &index, ImageD3D *image
int height = destBox ? destBox->height : static_cast<int>(image->getHeight());
int depth = destBox ? destBox->depth : static_cast<int>(image->getDepth());
UINT srcRowPitch = internalFormatInfo.computeRowPitch(type, width, unpack.alignment, unpack.rowLength);
- UINT srcDepthPitch = internalFormatInfo.computeDepthPitch(type, width, height, unpack.alignment, unpack.rowLength);
+ UINT srcDepthPitch = internalFormatInfo.computeDepthPitch(type, width, height, unpack.alignment,
+ unpack.rowLength, unpack.imageHeight);
+ GLsizei srcSkipBytes = internalFormatInfo.computeSkipPixels(
+ srcRowPitch, srcDepthPitch, unpack.skipImages, unpack.skipRows, unpack.skipPixels);
- const d3d11::TextureFormat &d3d11Format = d3d11::GetTextureFormatInfo(image->getInternalFormat(), mRenderer->getFeatureLevel());
+ const d3d11::TextureFormat &d3d11Format = d3d11::GetTextureFormatInfo(image->getInternalFormat(), mRenderer->getRenderer11DeviceCaps());
const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(d3d11Format.texFormat);
size_t outputPixelSize = dxgiFormatInfo.pixelBytes;
- UINT bufferRowPitch = outputPixelSize * width;
+ UINT bufferRowPitch = static_cast<unsigned int>(outputPixelSize) * width;
UINT bufferDepthPitch = bufferRowPitch * height;
size_t neededSize = bufferDepthPitch * depth;
- MemoryBuffer *conversionBuffer = NULL;
- error = mRenderer->getScratchMemoryBuffer(neededSize, &conversionBuffer);
- if (error.isError())
+ MemoryBuffer *conversionBuffer = nullptr;
+ const uint8_t *data = nullptr;
+
+ d3d11::LoadImageFunctionInfo loadFunctionInfo = d3d11Format.loadFunctions.at(type);
+ if (loadFunctionInfo.requiresConversion)
{
- return error;
- }
+ error = mRenderer->getScratchMemoryBuffer(neededSize, &conversionBuffer);
+ if (error.isError())
+ {
+ return error;
+ }
- // TODO: fast path
- LoadImageFunction loadFunction = d3d11Format.loadFunctions.at(type);
- loadFunction(width, height, depth,
- pixelData, srcRowPitch, srcDepthPitch,
- conversionBuffer->data(), bufferRowPitch, bufferDepthPitch);
+ loadFunctionInfo.loadFunction(width, height, depth, pixelData + srcSkipBytes, srcRowPitch,
+ srcDepthPitch, conversionBuffer->data(), bufferRowPitch,
+ bufferDepthPitch);
+ data = conversionBuffer->data();
+ }
+ else
+ {
+ data = pixelData + srcSkipBytes;
+ bufferRowPitch = srcRowPitch;
+ bufferDepthPitch = srcDepthPitch;
+ }
ID3D11DeviceContext *immediateContext = mRenderer->getDeviceContext();
@@ -588,27 +705,25 @@ gl::Error TextureStorage11::setData(const gl::ImageIndex &index, ImageD3D *image
destD3DBox.front = destBox->z;
destD3DBox.back = destBox->z + destBox->depth;
- immediateContext->UpdateSubresource(resource, destSubresource,
- &destD3DBox, conversionBuffer->data(),
+ immediateContext->UpdateSubresource(resource, destSubresource, &destD3DBox, data,
bufferRowPitch, bufferDepthPitch);
}
else
{
- immediateContext->UpdateSubresource(resource, destSubresource,
- NULL, conversionBuffer->data(),
- bufferRowPitch, bufferDepthPitch);
+ immediateContext->UpdateSubresource(resource, destSubresource, NULL, data, bufferRowPitch,
+ bufferDepthPitch);
}
return gl::Error(GL_NO_ERROR);
}
TextureStorage11_2D::TextureStorage11_2D(Renderer11 *renderer, SwapChain11 *swapchain)
- : TextureStorage11(renderer, D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE),
+ : TextureStorage11(renderer, D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE, 0),
mTexture(swapchain->getOffscreenTexture()),
- mSwizzleTexture(NULL),
mLevelZeroTexture(NULL),
mLevelZeroRenderTarget(NULL),
- mUseLevelZeroTexture(false)
+ mUseLevelZeroTexture(false),
+ mSwizzleTexture(NULL)
{
mTexture->AddRef();
@@ -627,7 +742,7 @@ TextureStorage11_2D::TextureStorage11_2D(Renderer11 *renderer, SwapChain11 *swap
mTextureHeight = texDesc.Height;
mTextureDepth = 1;
- mInternalFormat = swapchain->GetBackBufferInternalFormat();
+ mInternalFormat = swapchain->GetRenderTargetInternalFormat();
ID3D11ShaderResourceView *srv = swapchain->getRenderTargetShaderResource();
D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
@@ -640,23 +755,23 @@ TextureStorage11_2D::TextureStorage11_2D(Renderer11 *renderer, SwapChain11 *swap
mRenderTargetFormat = rtvDesc.Format;
const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(mTextureFormat);
- const d3d11::TextureFormat &formatInfo = d3d11::GetTextureFormatInfo(dxgiFormatInfo.internalFormat, mRenderer->getFeatureLevel());
+ const d3d11::TextureFormat &formatInfo = d3d11::GetTextureFormatInfo(dxgiFormatInfo.internalFormat, mRenderer->getRenderer11DeviceCaps());
mSwizzleTextureFormat = formatInfo.swizzleTexFormat;
mSwizzleShaderResourceFormat = formatInfo.swizzleSRVFormat;
mSwizzleRenderTargetFormat = formatInfo.swizzleRTVFormat;
mDepthStencilFormat = DXGI_FORMAT_UNKNOWN;
-
- initializeSerials(1, 1);
}
TextureStorage11_2D::TextureStorage11_2D(Renderer11 *renderer, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels, bool hintLevelZeroOnly)
- : TextureStorage11(renderer, GetTextureBindFlags(internalformat, renderer->getFeatureLevel(), renderTarget)),
+ : TextureStorage11(renderer,
+ GetTextureBindFlags(internalformat, renderer->getRenderer11DeviceCaps(), renderTarget),
+ GetTextureMiscFlags(internalformat, renderer->getRenderer11DeviceCaps(), renderTarget, levels)),
mTexture(NULL),
- mSwizzleTexture(NULL),
mLevelZeroTexture(NULL),
mLevelZeroRenderTarget(NULL),
- mUseLevelZeroTexture(false)
+ mUseLevelZeroTexture(false),
+ mSwizzleTexture(NULL)
{
for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
{
@@ -667,7 +782,7 @@ TextureStorage11_2D::TextureStorage11_2D(Renderer11 *renderer, GLenum internalfo
mInternalFormat = internalformat;
- const d3d11::TextureFormat &formatInfo = d3d11::GetTextureFormatInfo(internalformat, renderer->getFeatureLevel());
+ const d3d11::TextureFormat &formatInfo = d3d11::GetTextureFormatInfo(internalformat, renderer->getRenderer11DeviceCaps());
mTextureFormat = formatInfo.texFormat;
mShaderResourceFormat = formatInfo.srvFormat;
mDepthStencilFormat = formatInfo.dsvFormat;
@@ -688,8 +803,6 @@ TextureStorage11_2D::TextureStorage11_2D(Renderer11 *renderer, GLenum internalfo
ASSERT(mRenderer->getWorkarounds().zeroMaxLodWorkaround);
mUseLevelZeroTexture = true;
}
-
- initializeSerials(getLevelCount(), 1);
}
TextureStorage11_2D::~TextureStorage11_2D()
@@ -726,17 +839,11 @@ TextureStorage11_2D::~TextureStorage11_2D()
}
}
-TextureStorage11_2D *TextureStorage11_2D::makeTextureStorage11_2D(TextureStorage *storage)
-{
- ASSERT(HAS_DYNAMIC_TYPE(TextureStorage11_2D*, storage));
- return static_cast<TextureStorage11_2D*>(storage);
-}
-
gl::Error TextureStorage11_2D::copyToStorage(TextureStorage *destStorage)
{
ASSERT(destStorage);
- TextureStorage11_2D *dest11 = TextureStorage11_2D::makeTextureStorage11_2D(destStorage);
+ TextureStorage11_2D *dest11 = GetAs<TextureStorage11_2D>(destStorage);
if (mRenderer->getWorkarounds().zeroMaxLodWorkaround)
{
@@ -989,7 +1096,7 @@ gl::Error TextureStorage11_2D::ensureTextureExists(int mipLevels)
desc.Usage = D3D11_USAGE_DEFAULT;
desc.BindFlags = getBindFlags();
desc.CPUAccessFlags = 0;
- desc.MiscFlags = 0;
+ desc.MiscFlags = getMiscFlags();
HRESULT result = device->CreateTexture2D(&desc, NULL, outputTexture);
@@ -1004,6 +1111,8 @@ gl::Error TextureStorage11_2D::ensureTextureExists(int mipLevels)
ASSERT(result == E_OUTOFMEMORY);
return gl::Error(GL_OUT_OF_MEMORY, "Failed to create 2D texture storage, result: 0x%X.", result);
}
+
+ d3d11::SetDebugName(*outputTexture, "TexStorage2D.Texture");
}
return gl::Error(GL_NO_ERROR);
@@ -1021,7 +1130,7 @@ gl::Error TextureStorage11_2D::getRenderTarget(const gl::ImageIndex &index, Rend
// On Feature Level 9_3, this is unlikely to be useful. The renderer can't create SRVs on the individual levels of the texture,
// so methods like generateMipmap can't do anything useful with non-zero-level RTVs.
// Therefore if level > 0 on 9_3 then there's almost certainly something wrong.
- ASSERT(!(mRenderer->getFeatureLevel() <= D3D_FEATURE_LEVEL_9_3 && level > 0));
+ ASSERT(!(mRenderer->getRenderer11DeviceCaps().featureLevel <= D3D_FEATURE_LEVEL_9_3 && level > 0));
if (!mRenderTarget[level])
{
@@ -1170,6 +1279,8 @@ gl::Error TextureStorage11_2D::createSRV(int baseLevel, int mipLevels, DXGI_FORM
return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal texture storage SRV, result: 0x%X.", result);
}
+ d3d11::SetDebugName(*outSRV, "TexStorage2D.SRV");
+
return gl::Error(GL_NO_ERROR);
}
@@ -1201,6 +1312,8 @@ gl::Error TextureStorage11_2D::getSwizzleTexture(ID3D11Resource **outTexture)
{
return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal swizzle texture, result: 0x%X.", result);
}
+
+ d3d11::SetDebugName(mSwizzleTexture, "TexStorage2D.SwizzleTexture");
}
*outTexture = mSwizzleTexture;
@@ -1241,8 +1354,337 @@ gl::Error TextureStorage11_2D::getSwizzleRenderTarget(int mipLevel, ID3D11Render
return gl::Error(GL_NO_ERROR);
}
+TextureStorage11_EGLImage::TextureStorage11_EGLImage(Renderer11 *renderer, EGLImageD3D *eglImage)
+ : TextureStorage11(renderer, D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE, 0),
+ mImage(eglImage),
+ mCurrentRenderTarget(0),
+ mSwizzleTexture(nullptr),
+ mSwizzleRenderTargets(gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS, nullptr)
+{
+ RenderTargetD3D *renderTargetD3D = nullptr;
+ mImage->getRenderTarget(&renderTargetD3D);
+ RenderTarget11 *renderTarget11 = GetAs<RenderTarget11>(renderTargetD3D);
+ mCurrentRenderTarget = reinterpret_cast<uintptr_t>(renderTarget11);
+
+ mMipLevels = 1;
+ mTextureFormat = renderTarget11->getDXGIFormat();
+ mTextureWidth = renderTarget11->getWidth();
+ mTextureHeight = renderTarget11->getHeight();
+ mTextureDepth = 1;
+ mInternalFormat = renderTarget11->getInternalFormat();
+
+ ID3D11ShaderResourceView *srv = renderTarget11->getShaderResourceView();
+ D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
+ srv->GetDesc(&srvDesc);
+ mShaderResourceFormat = srvDesc.Format;
+
+ ID3D11RenderTargetView *rtv = renderTarget11->getRenderTargetView();
+ if (rtv != nullptr)
+ {
+ D3D11_RENDER_TARGET_VIEW_DESC rtvDesc;
+ rtv->GetDesc(&rtvDesc);
+ mRenderTargetFormat = rtvDesc.Format;
+ }
+ else
+ {
+ mRenderTargetFormat = DXGI_FORMAT_UNKNOWN;
+ }
+
+ ID3D11DepthStencilView *dsv = renderTarget11->getDepthStencilView();
+ if (dsv != nullptr)
+ {
+ D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc;
+ dsv->GetDesc(&dsvDesc);
+ mDepthStencilFormat = dsvDesc.Format;
+ }
+ else
+ {
+ mDepthStencilFormat = DXGI_FORMAT_UNKNOWN;
+ }
+
+ const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(mTextureFormat);
+ const d3d11::TextureFormat &formatInfo = d3d11::GetTextureFormatInfo(
+ dxgiFormatInfo.internalFormat, mRenderer->getRenderer11DeviceCaps());
+ mSwizzleTextureFormat = formatInfo.swizzleTexFormat;
+ mSwizzleShaderResourceFormat = formatInfo.swizzleSRVFormat;
+ mSwizzleRenderTargetFormat = formatInfo.swizzleRTVFormat;
+}
+
+TextureStorage11_EGLImage::~TextureStorage11_EGLImage()
+{
+ SafeRelease(mSwizzleTexture);
+ for (size_t i = 0; i < mSwizzleRenderTargets.size(); i++)
+ {
+ SafeRelease(mSwizzleRenderTargets[i]);
+ }
+}
+
+gl::Error TextureStorage11_EGLImage::getResource(ID3D11Resource **outResource)
+{
+ gl::Error error = checkForUpdatedRenderTarget();
+ if (error.isError())
+ {
+ return error;
+ }
+
+ RenderTarget11 *renderTarget11 = nullptr;
+ error = getImageRenderTarget(&renderTarget11);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ *outResource = renderTarget11->getTexture();
+ return gl::Error(GL_NO_ERROR);
+}
+
+gl::Error TextureStorage11_EGLImage::getSRV(const gl::TextureState &textureState,
+ ID3D11ShaderResourceView **outSRV)
+{
+ gl::Error error = checkForUpdatedRenderTarget();
+ if (error.isError())
+ {
+ return error;
+ }
+
+ return TextureStorage11::getSRV(textureState, outSRV);
+}
+
+gl::Error TextureStorage11_EGLImage::getMippedResource(ID3D11Resource **)
+{
+ // This shouldn't be called unless the zero max LOD workaround is active.
+ // EGL images are unavailable in this configuration.
+ UNREACHABLE();
+ return gl::Error(GL_INVALID_OPERATION);
+}
+
+gl::Error TextureStorage11_EGLImage::getRenderTarget(const gl::ImageIndex &index,
+ RenderTargetD3D **outRT)
+{
+ ASSERT(!index.hasLayer());
+ ASSERT(index.mipIndex == 0);
+ UNUSED_ASSERTION_VARIABLE(index);
+
+ gl::Error error = checkForUpdatedRenderTarget();
+ if (error.isError())
+ {
+ return error;
+ }
+
+ return mImage->getRenderTarget(outRT);
+}
+
+gl::Error TextureStorage11_EGLImage::copyToStorage(TextureStorage *destStorage)
+{
+ ID3D11Resource *sourceResouce = nullptr;
+ gl::Error error = getResource(&sourceResouce);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ ASSERT(destStorage);
+ TextureStorage11_2D *dest11 = GetAs<TextureStorage11_2D>(destStorage);
+ ID3D11Resource *destResource = nullptr;
+ error = dest11->getResource(&destResource);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ ID3D11DeviceContext *immediateContext = mRenderer->getDeviceContext();
+ immediateContext->CopyResource(destResource, sourceResouce);
+
+ dest11->invalidateSwizzleCache();
+
+ return gl::Error(GL_NO_ERROR);
+}
+
+void TextureStorage11_EGLImage::associateImage(Image11 *, const gl::ImageIndex &)
+{
+}
+
+void TextureStorage11_EGLImage::disassociateImage(const gl::ImageIndex &, Image11 *)
+{
+}
+
+bool TextureStorage11_EGLImage::isAssociatedImageValid(const gl::ImageIndex &, Image11 *)
+{
+ return false;
+}
+
+gl::Error TextureStorage11_EGLImage::releaseAssociatedImage(const gl::ImageIndex &, Image11 *)
+{
+ return gl::Error(GL_NO_ERROR);
+}
+
+gl::Error TextureStorage11_EGLImage::useLevelZeroWorkaroundTexture(bool)
+{
+ UNREACHABLE();
+ return gl::Error(GL_INVALID_OPERATION);
+}
+
+gl::Error TextureStorage11_EGLImage::getSwizzleTexture(ID3D11Resource **outTexture)
+{
+ ASSERT(outTexture);
+
+ if (!mSwizzleTexture)
+ {
+ ID3D11Device *device = mRenderer->getDevice();
+
+ D3D11_TEXTURE2D_DESC desc;
+ desc.Width = mTextureWidth;
+ desc.Height = mTextureHeight;
+ desc.MipLevels = mMipLevels;
+ desc.ArraySize = 1;
+ desc.Format = mSwizzleTextureFormat;
+ desc.SampleDesc.Count = 1;
+ desc.SampleDesc.Quality = 0;
+ desc.Usage = D3D11_USAGE_DEFAULT;
+ desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
+ desc.CPUAccessFlags = 0;
+ desc.MiscFlags = 0;
+
+ HRESULT result = device->CreateTexture2D(&desc, NULL, &mSwizzleTexture);
+
+ ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result));
+ if (FAILED(result))
+ {
+ return gl::Error(GL_OUT_OF_MEMORY,
+ "Failed to create internal swizzle texture, result: 0x%X.", result);
+ }
+
+ d3d11::SetDebugName(mSwizzleTexture, "TexStorageEGLImage.SwizzleTexture");
+ }
+
+ *outTexture = mSwizzleTexture;
+ return gl::Error(GL_NO_ERROR);
+}
+
+gl::Error TextureStorage11_EGLImage::getSwizzleRenderTarget(int mipLevel,
+ ID3D11RenderTargetView **outRTV)
+{
+ ASSERT(mipLevel >= 0 && mipLevel < getLevelCount());
+ ASSERT(outRTV);
+
+ if (!mSwizzleRenderTargets[mipLevel])
+ {
+ ID3D11Resource *swizzleTexture = NULL;
+ gl::Error error = getSwizzleTexture(&swizzleTexture);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ ID3D11Device *device = mRenderer->getDevice();
+
+ D3D11_RENDER_TARGET_VIEW_DESC rtvDesc;
+ rtvDesc.Format = mSwizzleRenderTargetFormat;
+ rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
+ rtvDesc.Texture2D.MipSlice = mTopLevel + mipLevel;
+
+ HRESULT result = device->CreateRenderTargetView(mSwizzleTexture, &rtvDesc,
+ &mSwizzleRenderTargets[mipLevel]);
+
+ ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result));
+ if (FAILED(result))
+ {
+ return gl::Error(GL_OUT_OF_MEMORY,
+ "Failed to create internal swizzle render target view, result: 0x%X.",
+ result);
+ }
+ }
+
+ *outRTV = mSwizzleRenderTargets[mipLevel];
+ return gl::Error(GL_NO_ERROR);
+}
+
+gl::Error TextureStorage11_EGLImage::checkForUpdatedRenderTarget()
+{
+ RenderTarget11 *renderTarget11 = nullptr;
+ gl::Error error = getImageRenderTarget(&renderTarget11);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ if (mCurrentRenderTarget != reinterpret_cast<uintptr_t>(renderTarget11))
+ {
+ clearSRVCache();
+ mCurrentRenderTarget = reinterpret_cast<uintptr_t>(renderTarget11);
+ }
+
+ return gl::Error(GL_NO_ERROR);
+}
+
+gl::Error TextureStorage11_EGLImage::createSRV(int baseLevel,
+ int mipLevels,
+ DXGI_FORMAT format,
+ ID3D11Resource *texture,
+ ID3D11ShaderResourceView **outSRV) const
+{
+ ASSERT(baseLevel == 0);
+ ASSERT(mipLevels == 1);
+ ASSERT(outSRV);
+
+ // Create a new SRV only for the swizzle texture. Otherwise just return the Image's
+ // RenderTarget's SRV.
+ if (texture == mSwizzleTexture)
+ {
+ D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
+ srvDesc.Format = format;
+ srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
+ srvDesc.Texture2D.MostDetailedMip = mTopLevel + baseLevel;
+ srvDesc.Texture2D.MipLevels = mipLevels;
+
+ ID3D11Device *device = mRenderer->getDevice();
+ HRESULT result = device->CreateShaderResourceView(texture, &srvDesc, outSRV);
+
+ ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result));
+ if (FAILED(result))
+ {
+ return gl::Error(GL_OUT_OF_MEMORY,
+ "Failed to create internal texture storage SRV, result: 0x%X.",
+ result);
+ }
+
+ d3d11::SetDebugName(*outSRV, "TexStorageEGLImage.SRV");
+ }
+ else
+ {
+ RenderTarget11 *renderTarget = nullptr;
+ gl::Error error = getImageRenderTarget(&renderTarget);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ ASSERT(texture == renderTarget->getTexture());
+
+ *outSRV = renderTarget->getShaderResourceView();
+ (*outSRV)->AddRef();
+ }
+
+ return gl::Error(GL_NO_ERROR);
+}
+
+gl::Error TextureStorage11_EGLImage::getImageRenderTarget(RenderTarget11 **outRT) const
+{
+ RenderTargetD3D *renderTargetD3D = nullptr;
+ gl::Error error = mImage->getRenderTarget(&renderTargetD3D);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ *outRT = GetAs<RenderTarget11>(renderTargetD3D);
+ return gl::Error(GL_NO_ERROR);
+}
+
TextureStorage11_Cube::TextureStorage11_Cube(Renderer11 *renderer, GLenum internalformat, bool renderTarget, int size, int levels, bool hintLevelZeroOnly)
- : TextureStorage11(renderer, GetTextureBindFlags(internalformat, renderer->getFeatureLevel(), renderTarget))
+ : TextureStorage11(renderer,
+ GetTextureBindFlags(internalformat, renderer->getRenderer11DeviceCaps(), renderTarget),
+ GetTextureMiscFlags(internalformat, renderer->getRenderer11DeviceCaps(), renderTarget, levels))
{
mTexture = NULL;
mSwizzleTexture = NULL;
@@ -1267,7 +1709,7 @@ TextureStorage11_Cube::TextureStorage11_Cube(Renderer11 *renderer, GLenum intern
mInternalFormat = internalformat;
- const d3d11::TextureFormat &formatInfo = d3d11::GetTextureFormatInfo(internalformat, renderer->getFeatureLevel());
+ const d3d11::TextureFormat &formatInfo = d3d11::GetTextureFormatInfo(internalformat, renderer->getRenderer11DeviceCaps());
mTextureFormat = formatInfo.texFormat;
mShaderResourceFormat = formatInfo.srvFormat;
mDepthStencilFormat = formatInfo.dsvFormat;
@@ -1291,8 +1733,6 @@ TextureStorage11_Cube::TextureStorage11_Cube(Renderer11 *renderer, GLenum intern
ASSERT(mRenderer->getWorkarounds().zeroMaxLodWorkaround);
mUseLevelZeroTexture = true;
}
-
- initializeSerials(getLevelCount() * CUBE_FACE_COUNT, CUBE_FACE_COUNT);
}
TextureStorage11_Cube::~TextureStorage11_Cube()
@@ -1334,12 +1774,6 @@ TextureStorage11_Cube::~TextureStorage11_Cube()
}
}
-TextureStorage11_Cube *TextureStorage11_Cube::makeTextureStorage11_Cube(TextureStorage *storage)
-{
- ASSERT(HAS_DYNAMIC_TYPE(TextureStorage11_Cube*, storage));
- return static_cast<TextureStorage11_Cube*>(storage);
-}
-
UINT TextureStorage11_Cube::getSubresourceIndex(const gl::ImageIndex &index) const
{
if (mRenderer->getWorkarounds().zeroMaxLodWorkaround && mUseLevelZeroTexture && index.mipIndex == 0)
@@ -1363,7 +1797,7 @@ gl::Error TextureStorage11_Cube::copyToStorage(TextureStorage *destStorage)
{
ASSERT(destStorage);
- TextureStorage11_Cube *dest11 = TextureStorage11_Cube::makeTextureStorage11_Cube(destStorage);
+ TextureStorage11_Cube *dest11 = GetAs<TextureStorage11_Cube>(destStorage);
if (mRenderer->getWorkarounds().zeroMaxLodWorkaround)
{
@@ -1643,7 +2077,7 @@ gl::Error TextureStorage11_Cube::ensureTextureExists(int mipLevels)
desc.Usage = D3D11_USAGE_DEFAULT;
desc.BindFlags = getBindFlags();
desc.CPUAccessFlags = 0;
- desc.MiscFlags = D3D11_RESOURCE_MISC_TEXTURECUBE;
+ desc.MiscFlags = D3D11_RESOURCE_MISC_TEXTURECUBE | getMiscFlags();
HRESULT result = device->CreateTexture2D(&desc, NULL, outputTexture);
@@ -1658,6 +2092,8 @@ gl::Error TextureStorage11_Cube::ensureTextureExists(int mipLevels)
ASSERT(result == E_OUTOFMEMORY);
return gl::Error(GL_OUT_OF_MEMORY, "Failed to create cube texture storage, result: 0x%X.", result);
}
+
+ d3d11::SetDebugName(*outputTexture, "TexStorageCube.Texture");
}
return gl::Error(GL_NO_ERROR);
@@ -1721,7 +2157,7 @@ gl::Error TextureStorage11_Cube::getRenderTarget(const gl::ImageIndex &index, Re
srvDesc.Texture2DArray.FirstArraySlice = faceIndex;
srvDesc.Texture2DArray.ArraySize = 1;
- if (mRenderer->getFeatureLevel() <= D3D_FEATURE_LEVEL_9_3)
+ if (mRenderer->getRenderer11DeviceCaps().featureLevel <= D3D_FEATURE_LEVEL_9_3)
{
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE;
}
@@ -1739,6 +2175,8 @@ gl::Error TextureStorage11_Cube::getRenderTarget(const gl::ImageIndex &index, Re
return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal shader resource view for texture storage, result: 0x%X.", result);
}
+ d3d11::SetDebugName(srv, "TexStorageCube.RenderTargetSRV");
+
if (mRenderTargetFormat != DXGI_FORMAT_UNKNOWN)
{
D3D11_RENDER_TARGET_VIEW_DESC rtvDesc;
@@ -1758,6 +2196,8 @@ gl::Error TextureStorage11_Cube::getRenderTarget(const gl::ImageIndex &index, Re
return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal render target view for texture storage, result: 0x%X.", result);
}
+ d3d11::SetDebugName(rtv, "TexStorageCube.RenderTargetRTV");
+
mRenderTarget[faceIndex][level] = new TextureRenderTarget11(rtv, texture, srv, mInternalFormat, getLevelWidth(level), getLevelHeight(level), 1, 0);
// RenderTarget will take ownership of these resources
@@ -1784,6 +2224,8 @@ gl::Error TextureStorage11_Cube::getRenderTarget(const gl::ImageIndex &index, Re
return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal depth stencil view for texture storage, result: 0x%X.", result);
}
+ d3d11::SetDebugName(dsv, "TexStorageCube.RenderTargetDSV");
+
mRenderTarget[faceIndex][level] = new TextureRenderTarget11(dsv, texture, srv, mInternalFormat, getLevelWidth(level), getLevelHeight(level), 1, 0);
// RenderTarget will take ownership of these resources
@@ -1815,7 +2257,7 @@ gl::Error TextureStorage11_Cube::createSRV(int baseLevel, int mipLevels, DXGI_FO
{
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY;
srvDesc.Texture2DArray.MostDetailedMip = mTopLevel + baseLevel;
- srvDesc.Texture2DArray.MipLevels = 1;
+ srvDesc.Texture2DArray.MipLevels = mipLevels;
srvDesc.Texture2DArray.FirstArraySlice = 0;
srvDesc.Texture2DArray.ArraySize = CUBE_FACE_COUNT;
}
@@ -1857,6 +2299,8 @@ gl::Error TextureStorage11_Cube::createSRV(int baseLevel, int mipLevels, DXGI_FO
return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal texture storage SRV, result: 0x%X.", result);
}
+ d3d11::SetDebugName(*outSRV, "TexStorageCube.SRV");
+
return gl::Error(GL_NO_ERROR);
}
@@ -1888,6 +2332,8 @@ gl::Error TextureStorage11_Cube::getSwizzleTexture(ID3D11Resource **outTexture)
{
return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal swizzle texture, result: 0x%X.", result);
}
+
+ d3d11::SetDebugName(*outTexture, "TexStorageCube.SwizzleTexture");
}
*outTexture = mSwizzleTexture;
@@ -1932,7 +2378,9 @@ gl::Error TextureStorage11_Cube::getSwizzleRenderTarget(int mipLevel, ID3D11Rend
TextureStorage11_3D::TextureStorage11_3D(Renderer11 *renderer, GLenum internalformat, bool renderTarget,
GLsizei width, GLsizei height, GLsizei depth, int levels)
- : TextureStorage11(renderer, GetTextureBindFlags(internalformat, renderer->getFeatureLevel(), renderTarget))
+ : TextureStorage11(renderer,
+ GetTextureBindFlags(internalformat, renderer->getRenderer11DeviceCaps(), renderTarget),
+ GetTextureMiscFlags(internalformat, renderer->getRenderer11DeviceCaps(), renderTarget, levels))
{
mTexture = NULL;
mSwizzleTexture = NULL;
@@ -1946,7 +2394,7 @@ TextureStorage11_3D::TextureStorage11_3D(Renderer11 *renderer, GLenum internalfo
mInternalFormat = internalformat;
- const d3d11::TextureFormat &formatInfo = d3d11::GetTextureFormatInfo(internalformat, renderer->getFeatureLevel());
+ const d3d11::TextureFormat &formatInfo = d3d11::GetTextureFormatInfo(internalformat, renderer->getRenderer11DeviceCaps());
mTextureFormat = formatInfo.texFormat;
mShaderResourceFormat = formatInfo.srvFormat;
mDepthStencilFormat = formatInfo.dsvFormat;
@@ -1962,8 +2410,6 @@ TextureStorage11_3D::TextureStorage11_3D(Renderer11 *renderer, GLenum internalfo
mTextureWidth = width;
mTextureHeight = height;
mTextureDepth = depth;
-
- initializeSerials(getLevelCount() * depth, depth);
}
TextureStorage11_3D::~TextureStorage11_3D()
@@ -1999,12 +2445,6 @@ TextureStorage11_3D::~TextureStorage11_3D()
}
}
-TextureStorage11_3D *TextureStorage11_3D::makeTextureStorage11_3D(TextureStorage *storage)
-{
- ASSERT(HAS_DYNAMIC_TYPE(TextureStorage11_3D*, storage));
- return static_cast<TextureStorage11_3D*>(storage);
-}
-
void TextureStorage11_3D::associateImage(Image11* image, const gl::ImageIndex &index)
{
GLint level = index.mipIndex;
@@ -2101,7 +2541,7 @@ gl::Error TextureStorage11_3D::getResource(ID3D11Resource **outResource)
desc.Usage = D3D11_USAGE_DEFAULT;
desc.BindFlags = getBindFlags();
desc.CPUAccessFlags = 0;
- desc.MiscFlags = 0;
+ desc.MiscFlags = getMiscFlags();
HRESULT result = device->CreateTexture3D(&desc, NULL, &mTexture);
@@ -2116,6 +2556,8 @@ gl::Error TextureStorage11_3D::getResource(ID3D11Resource **outResource)
ASSERT(result == E_OUTOFMEMORY);
return gl::Error(GL_OUT_OF_MEMORY, "Failed to create 3D texture storage, result: 0x%X.", result);
}
+
+ d3d11::SetDebugName(mTexture, "TexStorage3D.Texture");
}
*outResource = mTexture;
@@ -2142,6 +2584,8 @@ gl::Error TextureStorage11_3D::createSRV(int baseLevel, int mipLevels, DXGI_FORM
return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal texture storage SRV, result: 0x%X.", result);
}
+ d3d11::SetDebugName(*outSRV, "TexStorage3D.SRV");
+
return gl::Error(GL_NO_ERROR);
}
@@ -2189,6 +2633,8 @@ gl::Error TextureStorage11_3D::getRenderTarget(const gl::ImageIndex &index, Rend
return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal render target view for texture storage, result: 0x%X.", result);
}
+ d3d11::SetDebugName(rtv, "TexStorage3D.RTV");
+
mLevelRenderTargets[mipLevel] = new TextureRenderTarget11(rtv, texture, srv, mInternalFormat, getLevelWidth(mipLevel), getLevelHeight(mipLevel), getLevelDepth(mipLevel), 0);
// RenderTarget will take ownership of these resources
@@ -2236,6 +2682,8 @@ gl::Error TextureStorage11_3D::getRenderTarget(const gl::ImageIndex &index, Rend
}
ASSERT(SUCCEEDED(result));
+ d3d11::SetDebugName(rtv, "TexStorage3D.LayerRTV");
+
mLevelLayerRenderTargets[key] = new TextureRenderTarget11(rtv, texture, srv, mInternalFormat, getLevelWidth(mipLevel), getLevelHeight(mipLevel), 1, 0);
// RenderTarget will take ownership of these resources
@@ -2274,6 +2722,8 @@ gl::Error TextureStorage11_3D::getSwizzleTexture(ID3D11Resource **outTexture)
{
return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal swizzle texture, result: 0x%X.", result);
}
+
+ d3d11::SetDebugName(mSwizzleTexture, "TexStorage3D.SwizzleTexture");
}
*outTexture = mSwizzleTexture;
@@ -2310,6 +2760,8 @@ gl::Error TextureStorage11_3D::getSwizzleRenderTarget(int mipLevel, ID3D11Render
{
return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal swizzle render target view, result: 0x%X.", result);
}
+
+ d3d11::SetDebugName(mSwizzleTexture, "TexStorage3D.SwizzleRTV");
}
*outRTV = mSwizzleRenderTargets[mipLevel];
@@ -2318,7 +2770,9 @@ gl::Error TextureStorage11_3D::getSwizzleRenderTarget(int mipLevel, ID3D11Render
TextureStorage11_2DArray::TextureStorage11_2DArray(Renderer11 *renderer, GLenum internalformat, bool renderTarget,
GLsizei width, GLsizei height, GLsizei depth, int levels)
- : TextureStorage11(renderer, GetTextureBindFlags(internalformat, renderer->getFeatureLevel(), renderTarget))
+ : TextureStorage11(renderer,
+ GetTextureBindFlags(internalformat, renderer->getRenderer11DeviceCaps(), renderTarget),
+ GetTextureMiscFlags(internalformat, renderer->getRenderer11DeviceCaps(), renderTarget, levels))
{
mTexture = NULL;
mSwizzleTexture = NULL;
@@ -2330,7 +2784,7 @@ TextureStorage11_2DArray::TextureStorage11_2DArray(Renderer11 *renderer, GLenum
mInternalFormat = internalformat;
- const d3d11::TextureFormat &formatInfo = d3d11::GetTextureFormatInfo(internalformat, renderer->getFeatureLevel());
+ const d3d11::TextureFormat &formatInfo = d3d11::GetTextureFormatInfo(internalformat, renderer->getRenderer11DeviceCaps());
mTextureFormat = formatInfo.texFormat;
mShaderResourceFormat = formatInfo.srvFormat;
mDepthStencilFormat = formatInfo.dsvFormat;
@@ -2346,8 +2800,6 @@ TextureStorage11_2DArray::TextureStorage11_2DArray(Renderer11 *renderer, GLenum
mTextureWidth = width;
mTextureHeight = height;
mTextureDepth = depth;
-
- initializeSerials(getLevelCount() * depth, depth);
}
TextureStorage11_2DArray::~TextureStorage11_2DArray()
@@ -2383,12 +2835,6 @@ TextureStorage11_2DArray::~TextureStorage11_2DArray()
mRenderTargets.clear();
}
-TextureStorage11_2DArray *TextureStorage11_2DArray::makeTextureStorage11_2DArray(TextureStorage *storage)
-{
- ASSERT(HAS_DYNAMIC_TYPE(TextureStorage11_2DArray*, storage));
- return static_cast<TextureStorage11_2DArray*>(storage);
-}
-
void TextureStorage11_2DArray::associateImage(Image11* image, const gl::ImageIndex &index)
{
GLint level = index.mipIndex;
@@ -2486,7 +2932,7 @@ gl::Error TextureStorage11_2DArray::getResource(ID3D11Resource **outResource)
desc.Usage = D3D11_USAGE_DEFAULT;
desc.BindFlags = getBindFlags();
desc.CPUAccessFlags = 0;
- desc.MiscFlags = 0;
+ desc.MiscFlags = getMiscFlags();
HRESULT result = device->CreateTexture2D(&desc, NULL, &mTexture);
@@ -2501,6 +2947,8 @@ gl::Error TextureStorage11_2DArray::getResource(ID3D11Resource **outResource)
ASSERT(result == E_OUTOFMEMORY);
return gl::Error(GL_OUT_OF_MEMORY, "Failed to create 2D array texture storage, result: 0x%X.", result);
}
+
+ d3d11::SetDebugName(mTexture, "TexStorage2DArray.Texture");
}
*outResource = mTexture;
@@ -2527,6 +2975,8 @@ gl::Error TextureStorage11_2DArray::createSRV(int baseLevel, int mipLevels, DXGI
return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal texture storage SRV, result: 0x%X.", result);
}
+ d3d11::SetDebugName(*outSRV, "TexStorage2DArray.SRV");
+
return gl::Error(GL_NO_ERROR);
}
@@ -2569,6 +3019,8 @@ gl::Error TextureStorage11_2DArray::getRenderTarget(const gl::ImageIndex &index,
return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal shader resource view for texture storage, result: 0x%X.", result);
}
+ d3d11::SetDebugName(srv, "TexStorage2DArray.RenderTargetSRV");
+
if (mRenderTargetFormat != DXGI_FORMAT_UNKNOWN)
{
D3D11_RENDER_TARGET_VIEW_DESC rtvDesc;
@@ -2588,6 +3040,8 @@ gl::Error TextureStorage11_2DArray::getRenderTarget(const gl::ImageIndex &index,
return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal render target view for texture storage, result: 0x%X.", result);
}
+ d3d11::SetDebugName(rtv, "TexStorage2DArray.RenderTargetRTV");
+
mRenderTargets[key] = new TextureRenderTarget11(rtv, texture, srv, mInternalFormat, getLevelWidth(mipLevel), getLevelHeight(mipLevel), 1, 0);
// RenderTarget will take ownership of these resources
@@ -2631,6 +3085,8 @@ gl::Error TextureStorage11_2DArray::getSwizzleTexture(ID3D11Resource **outTextur
{
return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal swizzle texture, result: 0x%X.", result);
}
+
+ d3d11::SetDebugName(*outTexture, "TexStorage2DArray.SwizzleTexture");
}
*outTexture = mSwizzleTexture;
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/TextureStorage11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/TextureStorage11.h
index 456e2660f9..a88db2f0af 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/TextureStorage11.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/TextureStorage11.h
@@ -23,25 +23,28 @@ struct ImageIndex;
namespace rx
{
+class EGLImageD3D;
class RenderTargetD3D;
class RenderTarget11;
class Renderer11;
class SwapChain11;
class Image11;
+struct Renderer11DeviceCaps;
class TextureStorage11 : public TextureStorage
{
public:
virtual ~TextureStorage11();
- static TextureStorage11 *makeTextureStorage11(TextureStorage *storage);
-
- static DWORD GetTextureBindFlags(GLenum internalFormat, D3D_FEATURE_LEVEL featureLevel, bool renderTarget);
+ static DWORD GetTextureBindFlags(GLenum internalFormat, const Renderer11DeviceCaps &renderer11DeviceCaps, bool renderTarget);
+ static DWORD GetTextureMiscFlags(GLenum internalFormat, const Renderer11DeviceCaps &renderer11DeviceCaps, bool renderTarget, int levels);
UINT getBindFlags() const;
+ UINT getMiscFlags() const;
virtual gl::Error getResource(ID3D11Resource **outResource) = 0;
- virtual gl::Error getSRV(const gl::SamplerState &samplerState, ID3D11ShaderResourceView **outSRV);
+ virtual gl::Error getSRV(const gl::TextureState &textureState,
+ ID3D11ShaderResourceView **outSRV);
virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT) = 0;
virtual gl::Error generateMipmap(const gl::ImageIndex &sourceIndex, const gl::ImageIndex &destIndex);
@@ -49,6 +52,7 @@ class TextureStorage11 : public TextureStorage
virtual int getTopLevel() const;
virtual bool isRenderTarget() const;
virtual bool isManaged() const;
+ bool supportsNativeMipmapFunction() const override;
virtual int getLevelCount() const;
virtual UINT getSubresourceIndex(const gl::ImageIndex &index) const;
@@ -71,8 +75,10 @@ class TextureStorage11 : public TextureStorage
virtual gl::Error setData(const gl::ImageIndex &index, ImageD3D *image, const gl::Box *destBox, GLenum type,
const gl::PixelUnpackState &unpack, const uint8_t *pixelData);
+ gl::Error getSRVLevels(GLint baseLevel, GLint maxLevel, ID3D11ShaderResourceView **outSRV);
+
protected:
- TextureStorage11(Renderer11 *renderer, UINT bindFlags);
+ TextureStorage11(Renderer11 *renderer, UINT bindFlags, UINT miscFlags);
int getLevelWidth(int mipLevel) const;
int getLevelHeight(int mipLevel) const;
int getLevelDepth(int mipLevel) const;
@@ -89,6 +95,9 @@ class TextureStorage11 : public TextureStorage
void verifySwizzleExists(GLenum swizzleRed, GLenum swizzleGreen, GLenum swizzleBlue, GLenum swizzleAlpha);
+ // Clear all cached non-swizzle SRVs and invalidate the swizzle cache.
+ void clearSRVCache();
+
Renderer11 *mRenderer;
int mTopLevel;
unsigned int mMipLevels;
@@ -122,6 +131,7 @@ class TextureStorage11 : public TextureStorage
private:
const UINT mBindFlags;
+ const UINT mMiscFlags;
struct SRVKey
{
@@ -146,8 +156,6 @@ class TextureStorage11_2D : public TextureStorage11
TextureStorage11_2D(Renderer11 *renderer, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels, bool hintLevelZeroOnly = false);
virtual ~TextureStorage11_2D();
- static TextureStorage11_2D *makeTextureStorage11_2D(TextureStorage *storage);
-
virtual gl::Error getResource(ID3D11Resource **outResource);
virtual gl::Error getMippedResource(ID3D11Resource **outResource);
virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT);
@@ -194,14 +202,58 @@ class TextureStorage11_2D : public TextureStorage11
Image11 *mAssociatedImages[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS];
};
+class TextureStorage11_EGLImage final : public TextureStorage11
+{
+ public:
+ TextureStorage11_EGLImage(Renderer11 *renderer, EGLImageD3D *eglImage);
+ ~TextureStorage11_EGLImage() override;
+
+ gl::Error getResource(ID3D11Resource **outResource) override;
+ gl::Error getSRV(const gl::TextureState &textureState,
+ ID3D11ShaderResourceView **outSRV) override;
+ gl::Error getMippedResource(ID3D11Resource **outResource) override;
+ gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT) override;
+
+ gl::Error copyToStorage(TextureStorage *destStorage) override;
+
+ void associateImage(Image11 *image, const gl::ImageIndex &index) override;
+ void disassociateImage(const gl::ImageIndex &index, Image11 *expectedImage) override;
+ bool isAssociatedImageValid(const gl::ImageIndex &index, Image11 *expectedImage) override;
+ gl::Error releaseAssociatedImage(const gl::ImageIndex &index, Image11 *incomingImage) override;
+
+ gl::Error useLevelZeroWorkaroundTexture(bool useLevelZeroTexture) override;
+
+ protected:
+ gl::Error getSwizzleTexture(ID3D11Resource **outTexture) override;
+ gl::Error getSwizzleRenderTarget(int mipLevel, ID3D11RenderTargetView **outRTV) override;
+
+ private:
+ // Check if the EGL image's render target has been updated due to orphaning and delete
+ // any SRVs and other resources based on the image's old render target.
+ gl::Error checkForUpdatedRenderTarget();
+
+ gl::Error createSRV(int baseLevel,
+ int mipLevels,
+ DXGI_FORMAT format,
+ ID3D11Resource *texture,
+ ID3D11ShaderResourceView **outSRV) const override;
+
+ gl::Error getImageRenderTarget(RenderTarget11 **outRT) const;
+
+ EGLImageD3D *mImage;
+ uintptr_t mCurrentRenderTarget;
+
+ // Swizzle-related variables
+ ID3D11Texture2D *mSwizzleTexture;
+ std::vector<ID3D11RenderTargetView *> mSwizzleRenderTargets;
+};
+
class TextureStorage11_Cube : public TextureStorage11
{
public:
TextureStorage11_Cube(Renderer11 *renderer, GLenum internalformat, bool renderTarget, int size, int levels, bool hintLevelZeroOnly);
virtual ~TextureStorage11_Cube();
- static TextureStorage11_Cube *makeTextureStorage11_Cube(TextureStorage *storage);
-
virtual UINT getSubresourceIndex(const gl::ImageIndex &index) const;
virtual gl::Error getResource(ID3D11Resource **outResource);
@@ -250,8 +302,6 @@ class TextureStorage11_3D : public TextureStorage11
GLsizei width, GLsizei height, GLsizei depth, int levels);
virtual ~TextureStorage11_3D();
- static TextureStorage11_3D *makeTextureStorage11_3D(TextureStorage *storage);
-
virtual gl::Error getResource(ID3D11Resource **outResource);
// Handles both layer and non-layer RTs
@@ -290,8 +340,6 @@ class TextureStorage11_2DArray : public TextureStorage11
GLsizei width, GLsizei height, GLsizei depth, int levels);
virtual ~TextureStorage11_2DArray();
- static TextureStorage11_2DArray *makeTextureStorage11_2DArray(TextureStorage *storage);
-
virtual gl::Error getResource(ID3D11Resource **outResource);
virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT);
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Trim11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Trim11.h
index f232ad7e8e..4741e81601 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Trim11.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Trim11.h
@@ -31,7 +31,9 @@ class Trim11 : angle::NonCopyable
private:
Renderer11 *mRenderer;
+#if defined (ANGLE_ENABLE_WINDOWS_STORE)
EventRegistrationToken mApplicationSuspendedEventToken;
+#endif
void trim();
bool registerForRendererTrimRequest();
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/VertexArray11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/VertexArray11.h
index 78aad7d106..b397140e71 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/VertexArray11.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/VertexArray11.h
@@ -19,20 +19,11 @@ class Renderer11;
class VertexArray11 : public VertexArrayImpl
{
public:
- VertexArray11(Renderer11 *renderer)
- : VertexArrayImpl(),
- mRenderer(renderer)
+ VertexArray11(const gl::VertexArray::Data &data)
+ : VertexArrayImpl(data)
{
}
- virtual ~VertexArray11() { }
-
- virtual void setElementArrayBuffer(const gl::Buffer *buffer) { }
- virtual void setAttribute(size_t idx, const gl::VertexAttribute &attr) { }
- virtual void setAttributeDivisor(size_t idx, GLuint divisor) { }
- virtual void enableAttribute(size_t idx, bool enabledState) { }
-
- private:
- Renderer11 *mRenderer;
+ virtual ~VertexArray11() {}
};
}
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/VertexBuffer11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/VertexBuffer11.cpp
index adc64cef5e..098cefcd53 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/VertexBuffer11.cpp
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/VertexBuffer11.cpp
@@ -7,11 +7,14 @@
// VertexBuffer11.cpp: Defines the D3D11 VertexBuffer implementation.
#include "libANGLE/renderer/d3d/d3d11/VertexBuffer11.h"
-#include "libANGLE/renderer/d3d/d3d11/Buffer11.h"
-#include "libANGLE/renderer/d3d/d3d11/Renderer11.h"
-#include "libANGLE/renderer/d3d/d3d11/formatutils11.h"
+
#include "libANGLE/Buffer.h"
#include "libANGLE/VertexAttribute.h"
+#include "libANGLE/formatutils.h"
+#include "libANGLE/renderer/d3d/d3d11/Buffer11.h"
+#include "libANGLE/renderer/d3d/d3d11/formatutils11.h"
+#include "libANGLE/renderer/d3d/d3d11/Renderer11.h"
+#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h"
namespace rx
{
@@ -53,6 +56,15 @@ gl::Error VertexBuffer11::initialize(unsigned int size, bool dynamicUsage)
{
return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal vertex buffer of size, %lu.", size);
}
+
+ if (dynamicUsage)
+ {
+ d3d11::SetDebugName(mBuffer, "VertexBuffer11 (dynamic)");
+ }
+ else
+ {
+ d3d11::SetDebugName(mBuffer, "VertexBuffer11 (static)");
+ }
}
mBufferSize = size;
@@ -61,12 +73,6 @@ gl::Error VertexBuffer11::initialize(unsigned int size, bool dynamicUsage)
return gl::Error(GL_NO_ERROR);
}
-VertexBuffer11 *VertexBuffer11::makeVertexBuffer11(VertexBuffer *vetexBuffer)
-{
- ASSERT(HAS_DYNAMIC_TYPE(VertexBuffer11*, vetexBuffer));
- return static_cast<VertexBuffer11*>(vetexBuffer);
-}
-
gl::Error VertexBuffer11::mapResource()
{
if (mMappedResourceData == NULL)
@@ -98,16 +104,20 @@ void VertexBuffer11::hintUnmapResource()
}
}
-gl::Error VertexBuffer11::storeVertexAttributes(const gl::VertexAttribute &attrib, const gl::VertexAttribCurrentValueData &currentValue,
- GLint start, GLsizei count, GLsizei instances, unsigned int offset)
+gl::Error VertexBuffer11::storeVertexAttributes(const gl::VertexAttribute &attrib,
+ GLenum currentValueType,
+ GLint start,
+ GLsizei count,
+ GLsizei instances,
+ unsigned int offset,
+ const uint8_t *sourceData)
{
if (!mBuffer)
{
return gl::Error(GL_OUT_OF_MEMORY, "Internal vertex buffer is not initialized.");
}
- gl::Buffer *buffer = attrib.buffer.get();
- int inputStride = ComputeVertexAttributeStride(attrib);
+ int inputStride = static_cast<int>(ComputeVertexAttributeStride(attrib));
// This will map the resource if it isn't already mapped.
gl::Error error = mapResource();
@@ -118,36 +128,16 @@ gl::Error VertexBuffer11::storeVertexAttributes(const gl::VertexAttribute &attri
uint8_t *output = mMappedResourceData + offset;
- const uint8_t *input = NULL;
- if (attrib.enabled)
- {
- if (buffer)
- {
- BufferD3D *storage = GetImplAs<BufferD3D>(buffer);
- error = storage->getData(&input);
- if (error.isError())
- {
- return error;
- }
- input += static_cast<int>(attrib.offset);
- }
- else
- {
- input = static_cast<const uint8_t*>(attrib.pointer);
- }
- }
- else
- {
- input = reinterpret_cast<const uint8_t*>(currentValue.FloatValues);
- }
+ const uint8_t *input = sourceData;
if (instances == 0 || attrib.divisor == 0)
{
input += inputStride * start;
}
- gl::VertexFormat vertexFormat(attrib, currentValue.Type);
- const d3d11::VertexFormat &vertexFormatInfo = d3d11::GetVertexFormatInfo(vertexFormat, mRenderer->getFeatureLevel());
+ gl::VertexFormatType vertexFormatType = gl::GetVertexFormatType(attrib, currentValueType);
+ const D3D_FEATURE_LEVEL featureLevel = mRenderer->getRenderer11DeviceCaps().featureLevel;
+ const d3d11::VertexFormat &vertexFormatInfo = d3d11::GetVertexFormatInfo(vertexFormatType, featureLevel);
ASSERT(vertexFormatInfo.copyFunction != NULL);
vertexFormatInfo.copyFunction(input, inputStride, count, output);
@@ -170,8 +160,9 @@ gl::Error VertexBuffer11::getSpaceRequired(const gl::VertexAttribute &attrib, GL
elementCount = UnsignedCeilDivide(static_cast<unsigned int>(instances), attrib.divisor);
}
- gl::VertexFormat vertexFormat(attrib);
- const d3d11::VertexFormat &vertexFormatInfo = d3d11::GetVertexFormatInfo(vertexFormat, mRenderer->getFeatureLevel());
+ gl::VertexFormatType formatType = gl::GetVertexFormatType(attrib);
+ const D3D_FEATURE_LEVEL featureLevel = mRenderer->getRenderer11DeviceCaps().featureLevel;
+ const d3d11::VertexFormat &vertexFormatInfo = d3d11::GetVertexFormatInfo(formatType, featureLevel);
const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(vertexFormatInfo.nativeFormat);
unsigned int elementSize = dxgiFormatInfo.pixelBytes;
if (elementSize <= std::numeric_limits<unsigned int>::max() / elementCount)
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/VertexBuffer11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/VertexBuffer11.h
index 2450e8955c..773c4474e1 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/VertexBuffer11.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/VertexBuffer11.h
@@ -25,10 +25,13 @@ class VertexBuffer11 : public VertexBuffer
virtual gl::Error initialize(unsigned int size, bool dynamicUsage);
- static VertexBuffer11 *makeVertexBuffer11(VertexBuffer *vetexBuffer);
-
- virtual gl::Error storeVertexAttributes(const gl::VertexAttribute &attrib, const gl::VertexAttribCurrentValueData &currentValue,
- GLint start, GLsizei count, GLsizei instances, unsigned int offset);
+ gl::Error storeVertexAttributes(const gl::VertexAttribute &attrib,
+ GLenum currentValueType,
+ GLint start,
+ GLsizei count,
+ GLsizei instances,
+ unsigned int offset,
+ const uint8_t *sourceData) override;
virtual gl::Error getSpaceRequired(const gl::VertexAttribute &attrib, GLsizei count, GLsizei instances,
unsigned int *outSpaceRequired) const;
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/copyvertex.inl b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/copyvertex.inl
index 60678d7b9f..1ec21dee55 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/copyvertex.inl
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/copyvertex.inl
@@ -245,17 +245,17 @@ static inline void CopyPackedRGB(uint32_t data, uint8_t *output)
if (data & rgbSignMask)
{
- *intOutput = data | negativeMask;
+ *intOutput = static_cast<GLshort>(data | negativeMask);
}
else
{
- *intOutput = data;
+ *intOutput = static_cast<GLshort>(data);
}
}
else
{
GLushort *uintOutput = reinterpret_cast<GLushort*>(output);
- *uintOutput = data;
+ *uintOutput = static_cast<GLushort>(data);
}
}
}
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/dxgi_support_data.json b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/dxgi_support_data.json
new file mode 100644
index 0000000000..e81b4deea5
--- /dev/null
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/dxgi_support_data.json
@@ -0,0 +1,1164 @@
+[
+ {
+ "DXGI_FORMAT_UNKNOWN":
+ {
+ "texture2D": "never",
+ "texture3D": "never",
+ "textureCube": "never",
+ "shaderSample": "never",
+ "renderTarget": "never",
+ "multisampleRT": "never",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_R32G32B32A32_TYPELESS":
+ {
+ "texture2D": "always",
+ "texture3D": "always",
+ "textureCube": "always",
+ "shaderSample": "never",
+ "renderTarget": "never",
+ "multisampleRT": "never",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_R32G32B32A32_FLOAT":
+ {
+ "texture2D": "always",
+ "texture3D": "always",
+ "textureCube": "always",
+ "shaderSample": "10_0check10_1always",
+ "renderTarget": "always",
+ "multisampleRT": "check",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_R32G32B32A32_UINT":
+ {
+ "texture2D": "always",
+ "texture3D": "always",
+ "textureCube": "always",
+ "shaderSample": "never",
+ "renderTarget": "always",
+ "multisampleRT": "check",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_R32G32B32A32_SINT":
+ {
+ "texture2D": "always",
+ "texture3D": "always",
+ "textureCube": "always",
+ "shaderSample": "never",
+ "renderTarget": "always",
+ "multisampleRT": "check",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_R32G32B32_TYPELESS":
+ {
+ "texture2D": "always",
+ "texture3D": "always",
+ "textureCube": "always",
+ "shaderSample": "never",
+ "renderTarget": "never",
+ "multisampleRT": "never",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_R32G32B32_FLOAT":
+ {
+ "texture2D": "always",
+ "texture3D": "always",
+ "textureCube": "always",
+ "shaderSample": "11_0check",
+ "renderTarget": "check",
+ "multisampleRT": "check",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_R32G32B32_UINT":
+ {
+ "texture2D": "always",
+ "texture3D": "always",
+ "textureCube": "always",
+ "shaderSample": "never",
+ "renderTarget": "check",
+ "multisampleRT": "check",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_R32G32B32_SINT":
+ {
+ "texture2D": "always",
+ "texture3D": "always",
+ "textureCube": "always",
+ "shaderSample": "never",
+ "renderTarget": "check",
+ "multisampleRT": "check",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_R16G16B16A16_TYPELESS":
+ {
+ "texture2D": "always",
+ "texture3D": "always",
+ "textureCube": "always",
+ "shaderSample": "never",
+ "renderTarget": "never",
+ "multisampleRT": "never",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_R16G16B16A16_FLOAT":
+ {
+ "texture2D": "always",
+ "texture3D": "always",
+ "textureCube": "always",
+ "shaderSample": "10_0",
+ "renderTarget": "always",
+ "multisampleRT": "check",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_R16G16B16A16_UNORM":
+ {
+ "texture2D": "always",
+ "texture3D": "always",
+ "textureCube": "always",
+ "shaderSample": "10_0",
+ "renderTarget": "always",
+ "multisampleRT": "check",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_R16G16B16A16_UINT":
+ {
+ "texture2D": "always",
+ "texture3D": "always",
+ "textureCube": "always",
+ "shaderSample": "never",
+ "renderTarget": "always",
+ "multisampleRT": "check",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_R16G16B16A16_SNORM":
+ {
+ "texture2D": "always",
+ "texture3D": "always",
+ "textureCube": "always",
+ "shaderSample": "10_0",
+ "renderTarget": "always",
+ "multisampleRT": "check",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_R16G16B16A16_SINT":
+ {
+ "texture2D": "always",
+ "texture3D": "always",
+ "textureCube": "always",
+ "shaderSample": "never",
+ "renderTarget": "always",
+ "multisampleRT": "check",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_R32G32_TYPELESS":
+ {
+ "texture2D": "always",
+ "texture3D": "always",
+ "textureCube": "always",
+ "shaderSample": "never",
+ "renderTarget": "never",
+ "multisampleRT": "never",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_R32G32_FLOAT":
+ {
+ "texture2D": "always",
+ "texture3D": "always",
+ "textureCube": "always",
+ "shaderSample": "10_0check10_1always",
+ "renderTarget": "always",
+ "multisampleRT": "check",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_R32G32_UINT":
+ {
+ "texture2D": "always",
+ "texture3D": "always",
+ "textureCube": "always",
+ "shaderSample": "never",
+ "renderTarget": "always",
+ "multisampleRT": "check",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_R32G32_SINT":
+ {
+ "texture2D": "always",
+ "texture3D": "always",
+ "textureCube": "always",
+ "shaderSample": "never",
+ "renderTarget": "always",
+ "multisampleRT": "check",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_R32G8X24_TYPELESS":
+ {
+ "texture2D": "always",
+ "texture3D": "never",
+ "textureCube": "always",
+ "shaderSample": "never",
+ "renderTarget": "never",
+ "multisampleRT": "never",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_D32_FLOAT_S8X24_UINT":
+ {
+ "texture2D": "always",
+ "texture3D": "never",
+ "textureCube": "always",
+ "shaderSample": "never",
+ "renderTarget": "never",
+ "multisampleRT": "check",
+ "depthStencil": "always"
+ },
+ "DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS":
+ {
+ "texture2D": "always",
+ "texture3D": "never",
+ "textureCube": "always",
+ "shaderSample": "10_0check10_1always",
+ "renderTarget": "never",
+ "multisampleRT": "never",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_X32_TYPELESS_G8X24_UINT":
+ {
+ "texture2D": "always",
+ "texture3D": "never",
+ "textureCube": "always",
+ "shaderSample": "never",
+ "renderTarget": "never",
+ "multisampleRT": "never",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_R10G10B10A2_TYPELESS":
+ {
+ "texture2D": "always",
+ "texture3D": "always",
+ "textureCube": "always",
+ "shaderSample": "never",
+ "renderTarget": "never",
+ "multisampleRT": "never",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_R10G10B10A2_UNORM":
+ {
+ "texture2D": "always",
+ "texture3D": "always",
+ "textureCube": "always",
+ "shaderSample": "10_0",
+ "renderTarget": "always",
+ "multisampleRT": "check",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_R10G10B10A2_UINT":
+ {
+ "texture2D": "always",
+ "texture3D": "always",
+ "textureCube": "always",
+ "shaderSample": "never",
+ "renderTarget": "always",
+ "multisampleRT": "check",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_R11G11B10_FLOAT":
+ {
+ "texture2D": "always",
+ "texture3D": "always",
+ "textureCube": "always",
+ "shaderSample": "10_0",
+ "renderTarget": "always",
+ "multisampleRT": "check",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_R8G8B8A8_TYPELESS":
+ {
+ "texture2D": "always",
+ "texture3D": "always",
+ "textureCube": "always",
+ "shaderSample": "never",
+ "renderTarget": "never",
+ "multisampleRT": "never",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_R8G8B8A8_UNORM":
+ {
+ "texture2D": "always",
+ "texture3D": "always",
+ "textureCube": "always",
+ "shaderSample": "10_0",
+ "renderTarget": "always",
+ "multisampleRT": "check",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_R8G8B8A8_UNORM_SRGB":
+ {
+ "texture2D": "always",
+ "texture3D": "always",
+ "textureCube": "always",
+ "shaderSample": "10_0",
+ "renderTarget": "always",
+ "multisampleRT": "check",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_R8G8B8A8_UINT":
+ {
+ "texture2D": "always",
+ "texture3D": "always",
+ "textureCube": "always",
+ "shaderSample": "never",
+ "renderTarget": "always",
+ "multisampleRT": "check",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_R8G8B8A8_SNORM":
+ {
+ "texture2D": "always",
+ "texture3D": "always",
+ "textureCube": "always",
+ "shaderSample": "10_0",
+ "renderTarget": "always",
+ "multisampleRT": "check",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_R8G8B8A8_SINT":
+ {
+ "texture2D": "always",
+ "texture3D": "always",
+ "textureCube": "always",
+ "shaderSample": "never",
+ "renderTarget": "always",
+ "multisampleRT": "check",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_R16G16_TYPELESS":
+ {
+ "texture2D": "always",
+ "texture3D": "always",
+ "textureCube": "always",
+ "shaderSample": "never",
+ "renderTarget": "never",
+ "multisampleRT": "never",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_R16G16_FLOAT":
+ {
+ "texture2D": "always",
+ "texture3D": "always",
+ "textureCube": "always",
+ "shaderSample": "10_0",
+ "renderTarget": "always",
+ "multisampleRT": "check",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_R16G16_UNORM":
+ {
+ "texture2D": "always",
+ "texture3D": "always",
+ "textureCube": "always",
+ "shaderSample": "10_0",
+ "renderTarget": "always",
+ "multisampleRT": "check",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_R16G16_UINT":
+ {
+ "texture2D": "always",
+ "texture3D": "always",
+ "textureCube": "always",
+ "shaderSample": "never",
+ "renderTarget": "always",
+ "multisampleRT": "check",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_R16G16_SNORM":
+ {
+ "texture2D": "always",
+ "texture3D": "always",
+ "textureCube": "always",
+ "shaderSample": "10_0",
+ "renderTarget": "always",
+ "multisampleRT": "check",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_R16G16_SINT":
+ {
+ "texture2D": "always",
+ "texture3D": "always",
+ "textureCube": "always",
+ "shaderSample": "never",
+ "renderTarget": "always",
+ "multisampleRT": "check",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_R32_TYPELESS":
+ {
+ "texture2D": "always",
+ "texture3D": "always",
+ "textureCube": "always",
+ "shaderSample": "never",
+ "renderTarget": "never",
+ "multisampleRT": "never",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_D32_FLOAT":
+ {
+ "texture2D": "always",
+ "texture3D": "never",
+ "textureCube": "always",
+ "shaderSample": "never",
+ "renderTarget": "never",
+ "multisampleRT": "check",
+ "depthStencil": "always"
+ },
+ "DXGI_FORMAT_R32_FLOAT":
+ {
+ "texture2D": "always",
+ "texture3D": "always",
+ "textureCube": "always",
+ "shaderSample": "10_0check10_1always",
+ "renderTarget": "always",
+ "multisampleRT": "check",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_R32_UINT":
+ {
+ "texture2D": "always",
+ "texture3D": "always",
+ "textureCube": "always",
+ "shaderSample": "never",
+ "renderTarget": "always",
+ "multisampleRT": "check",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_R32_SINT":
+ {
+ "texture2D": "always",
+ "texture3D": "always",
+ "textureCube": "always",
+ "shaderSample": "never",
+ "renderTarget": "always",
+ "multisampleRT": "check",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_R24G8_TYPELESS":
+ {
+ "texture2D": "always",
+ "texture3D": "never",
+ "textureCube": "always",
+ "shaderSample": "never",
+ "renderTarget": "never",
+ "multisampleRT": "never",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_D24_UNORM_S8_UINT":
+ {
+ "texture2D": "always",
+ "texture3D": "never",
+ "textureCube": "always",
+ "shaderSample": "never",
+ "renderTarget": "never",
+ "multisampleRT": "check",
+ "depthStencil": "always"
+ },
+ "DXGI_FORMAT_R24_UNORM_X8_TYPELESS":
+ {
+ "texture2D": "always",
+ "texture3D": "never",
+ "textureCube": "always",
+ "shaderSample": "10_0check10_1always",
+ "renderTarget": "never",
+ "multisampleRT": "never",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_X24_TYPELESS_G8_UINT":
+ {
+ "texture2D": "always",
+ "texture3D": "never",
+ "textureCube": "always",
+ "shaderSample": "never",
+ "renderTarget": "never",
+ "multisampleRT": "never",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_R8G8_TYPELESS":
+ {
+ "texture2D": "always",
+ "texture3D": "always",
+ "textureCube": "always",
+ "shaderSample": "never",
+ "renderTarget": "never",
+ "multisampleRT": "never",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_R8G8_UNORM":
+ {
+ "texture2D": "always",
+ "texture3D": "always",
+ "textureCube": "always",
+ "shaderSample": "10_0",
+ "renderTarget": "always",
+ "multisampleRT": "check",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_R8G8_UINT":
+ {
+ "texture2D": "always",
+ "texture3D": "always",
+ "textureCube": "always",
+ "shaderSample": "never",
+ "renderTarget": "always",
+ "multisampleRT": "check",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_R8G8_SNORM":
+ {
+ "texture2D": "always",
+ "texture3D": "always",
+ "textureCube": "always",
+ "shaderSample": "10_0",
+ "renderTarget": "always",
+ "multisampleRT": "check",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_R8G8_SINT":
+ {
+ "texture2D": "always",
+ "texture3D": "always",
+ "textureCube": "always",
+ "shaderSample": "never",
+ "renderTarget": "always",
+ "multisampleRT": "check",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_R16_TYPELESS":
+ {
+ "texture2D": "always",
+ "texture3D": "always",
+ "textureCube": "always",
+ "shaderSample": "never",
+ "renderTarget": "never",
+ "multisampleRT": "never",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_R16_FLOAT":
+ {
+ "texture2D": "always",
+ "texture3D": "always",
+ "textureCube": "always",
+ "shaderSample": "10_0",
+ "renderTarget": "always",
+ "multisampleRT": "check",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_D16_UNORM":
+ {
+ "texture2D": "always",
+ "texture3D": "never",
+ "textureCube": "always",
+ "shaderSample": "never",
+ "renderTarget": "never",
+ "multisampleRT": "check",
+ "depthStencil": "always"
+ },
+ "DXGI_FORMAT_R16_UNORM":
+ {
+ "texture2D": "always",
+ "texture3D": "always",
+ "textureCube": "always",
+ "shaderSample": "10_0",
+ "renderTarget": "always",
+ "multisampleRT": "check",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_R16_UINT":
+ {
+ "texture2D": "always",
+ "texture3D": "always",
+ "textureCube": "always",
+ "shaderSample": "never",
+ "renderTarget": "always",
+ "multisampleRT": "check",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_R16_SNORM":
+ {
+ "texture2D": "always",
+ "texture3D": "always",
+ "textureCube": "always",
+ "shaderSample": "10_0",
+ "renderTarget": "always",
+ "multisampleRT": "check",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_R16_SINT":
+ {
+ "texture2D": "always",
+ "texture3D": "always",
+ "textureCube": "always",
+ "shaderSample": "never",
+ "renderTarget": "always",
+ "multisampleRT": "check",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_R8_TYPELESS":
+ {
+ "texture2D": "always",
+ "texture3D": "always",
+ "textureCube": "always",
+ "shaderSample": "never",
+ "renderTarget": "never",
+ "multisampleRT": "never",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_R8_UNORM":
+ {
+ "texture2D": "always",
+ "texture3D": "always",
+ "textureCube": "always",
+ "shaderSample": "10_0",
+ "renderTarget": "always",
+ "multisampleRT": "check",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_R8_UINT":
+ {
+ "texture2D": "always",
+ "texture3D": "always",
+ "textureCube": "always",
+ "shaderSample": "never",
+ "renderTarget": "always",
+ "multisampleRT": "check",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_R8_SNORM":
+ {
+ "texture2D": "always",
+ "texture3D": "always",
+ "textureCube": "always",
+ "shaderSample": "10_0",
+ "renderTarget": "always",
+ "multisampleRT": "check",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_R8_SINT":
+ {
+ "texture2D": "always",
+ "texture3D": "always",
+ "textureCube": "always",
+ "shaderSample": "never",
+ "renderTarget": "always",
+ "multisampleRT": "check",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_A8_UNORM":
+ {
+ "texture2D": "always",
+ "texture3D": "always",
+ "textureCube": "always",
+ "shaderSample": "10_0",
+ "renderTarget": "always",
+ "multisampleRT": "check",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_R1_UNORM":
+ {
+ "texture2D": "always",
+ "texture3D": "11_0",
+ "textureCube": "11_0",
+ "shaderSample": "never",
+ "renderTarget": "never",
+ "multisampleRT": "never",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_R9G9B9E5_SHAREDEXP":
+ {
+ "texture2D": "always",
+ "texture3D": "always",
+ "textureCube": "always",
+ "shaderSample": "10_0",
+ "renderTarget": "never",
+ "multisampleRT": "never",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_R8G8_B8G8_UNORM":
+ {
+ "texture2D": "always",
+ "texture3D": "always",
+ "textureCube": "always",
+ "shaderSample": "10_0",
+ "renderTarget": "never",
+ "multisampleRT": "never",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_G8R8_G8B8_UNORM":
+ {
+ "texture2D": "always",
+ "texture3D": "always",
+ "textureCube": "always",
+ "shaderSample": "10_0",
+ "renderTarget": "never",
+ "multisampleRT": "never",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_BC1_TYPELESS":
+ {
+ "texture2D": "always",
+ "texture3D": "always",
+ "textureCube": "always",
+ "shaderSample": "never",
+ "renderTarget": "never",
+ "multisampleRT": "never",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_BC1_UNORM":
+ {
+ "texture2D": "always",
+ "texture3D": "always",
+ "textureCube": "always",
+ "shaderSample": "10_0",
+ "renderTarget": "never",
+ "multisampleRT": "never",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_BC1_UNORM_SRGB":
+ {
+ "texture2D": "always",
+ "texture3D": "always",
+ "textureCube": "always",
+ "shaderSample": "10_0",
+ "renderTarget": "never",
+ "multisampleRT": "never",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_BC2_TYPELESS":
+ {
+ "texture2D": "always",
+ "texture3D": "always",
+ "textureCube": "always",
+ "shaderSample": "never",
+ "renderTarget": "never",
+ "multisampleRT": "never",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_BC2_UNORM":
+ {
+ "texture2D": "always",
+ "texture3D": "always",
+ "textureCube": "always",
+ "shaderSample": "10_0",
+ "renderTarget": "never",
+ "multisampleRT": "never",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_BC2_UNORM_SRGB":
+ {
+ "texture2D": "always",
+ "texture3D": "always",
+ "textureCube": "always",
+ "shaderSample": "10_0",
+ "renderTarget": "never",
+ "multisampleRT": "never",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_BC3_TYPELESS":
+ {
+ "texture2D": "always",
+ "texture3D": "always",
+ "textureCube": "always",
+ "shaderSample": "never",
+ "renderTarget": "never",
+ "multisampleRT": "never",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_BC3_UNORM":
+ {
+ "texture2D": "always",
+ "texture3D": "always",
+ "textureCube": "always",
+ "shaderSample": "10_0",
+ "renderTarget": "never",
+ "multisampleRT": "never",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_BC3_UNORM_SRGB":
+ {
+ "texture2D": "always",
+ "texture3D": "always",
+ "textureCube": "always",
+ "shaderSample": "10_0",
+ "renderTarget": "never",
+ "multisampleRT": "never",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_BC4_TYPELESS":
+ {
+ "texture2D": "always",
+ "texture3D": "always",
+ "textureCube": "always",
+ "shaderSample": "never",
+ "renderTarget": "never",
+ "multisampleRT": "never",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_BC4_UNORM":
+ {
+ "texture2D": "always",
+ "texture3D": "always",
+ "textureCube": "always",
+ "shaderSample": "10_0",
+ "renderTarget": "never",
+ "multisampleRT": "never",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_BC4_SNORM":
+ {
+ "texture2D": "always",
+ "texture3D": "always",
+ "textureCube": "always",
+ "shaderSample": "10_0",
+ "renderTarget": "never",
+ "multisampleRT": "never",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_BC5_TYPELESS":
+ {
+ "texture2D": "always",
+ "texture3D": "always",
+ "textureCube": "always",
+ "shaderSample": "never",
+ "renderTarget": "never",
+ "multisampleRT": "never",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_BC5_UNORM":
+ {
+ "texture2D": "always",
+ "texture3D": "always",
+ "textureCube": "always",
+ "shaderSample": "10_0",
+ "renderTarget": "never",
+ "multisampleRT": "never",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_BC5_SNORM":
+ {
+ "texture2D": "always",
+ "texture3D": "always",
+ "textureCube": "always",
+ "shaderSample": "10_0",
+ "renderTarget": "never",
+ "multisampleRT": "never",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_B5G6R5_UNORM":
+ {
+ "texture2D": "dxgi1_2",
+ "texture3D": "dxgi1_2",
+ "textureCube": "dxgi1_2",
+ "shaderSample": "dxgi1_2",
+ "renderTarget": "dxgi1_2",
+ "multisampleRT": "check",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_B5G5R5A1_UNORM":
+ {
+ "texture2D": "dxgi1_2",
+ "texture3D": "dxgi1_2",
+ "textureCube": "dxgi1_2",
+ "shaderSample": "dxgi1_2",
+ "renderTarget": "check",
+ "multisampleRT": "check",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_B8G8R8A8_UNORM":
+ {
+ "texture2D": "check",
+ "texture3D": "check",
+ "textureCube": "check",
+ "shaderSample": "10_0check11_0always",
+ "renderTarget": "10_0check11_0always",
+ "multisampleRT": "check",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_B8G8R8X8_UNORM":
+ {
+ "texture2D": "check",
+ "texture3D": "check",
+ "textureCube": "check",
+ "shaderSample": "10_0check11_0always",
+ "renderTarget": "11_0",
+ "multisampleRT": "check",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM":
+ {
+ "texture2D": "check",
+ "texture3D": "check",
+ "textureCube": "never",
+ "shaderSample": "never",
+ "renderTarget": "never",
+ "multisampleRT": "never",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_B8G8R8A8_TYPELESS":
+ {
+ "texture2D": "check",
+ "texture3D": "check",
+ "textureCube": "check",
+ "shaderSample": "never",
+ "renderTarget": "never",
+ "multisampleRT": "never",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_B8G8R8A8_UNORM_SRGB":
+ {
+ "texture2D": "check",
+ "texture3D": "check",
+ "textureCube": "check",
+ "shaderSample": "10_0check11_0always",
+ "renderTarget": "11_0",
+ "multisampleRT": "check",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_B8G8R8X8_TYPELESS":
+ {
+ "texture2D": "check",
+ "texture3D": "check",
+ "textureCube": "check",
+ "shaderSample": "never",
+ "renderTarget": "never",
+ "multisampleRT": "never",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_B8G8R8X8_UNORM_SRGB":
+ {
+ "texture2D": "check",
+ "texture3D": "check",
+ "textureCube": "check",
+ "shaderSample": "10_0check11_0always",
+ "renderTarget": "11_0",
+ "multisampleRT": "check",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_BC6H_TYPELESS":
+ {
+ "texture2D": "11_0",
+ "texture3D": "11_0",
+ "textureCube": "11_0",
+ "shaderSample": "never",
+ "renderTarget": "never",
+ "multisampleRT": "never",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_BC6H_UF16":
+ {
+ "texture2D": "11_0",
+ "texture3D": "11_0",
+ "textureCube": "11_0",
+ "shaderSample": "11_0",
+ "renderTarget": "never",
+ "multisampleRT": "never",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_BC6H_SF16":
+ {
+ "texture2D": "11_0",
+ "texture3D": "11_0",
+ "textureCube": "11_0",
+ "shaderSample": "11_0",
+ "renderTarget": "never",
+ "multisampleRT": "never",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_BC7_TYPELESS":
+ {
+ "texture2D": "11_0",
+ "texture3D": "11_0",
+ "textureCube": "11_0",
+ "shaderSample": "never",
+ "renderTarget": "never",
+ "multisampleRT": "never",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_BC7_UNORM":
+ {
+ "texture2D": "11_0",
+ "texture3D": "11_0",
+ "textureCube": "11_0",
+ "shaderSample": "11_0",
+ "renderTarget": "never",
+ "multisampleRT": "never",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_BC7_UNORM_SRGB":
+ {
+ "texture2D": "11_0",
+ "texture3D": "11_0",
+ "textureCube": "11_0",
+ "shaderSample": "11_0",
+ "renderTarget": "never",
+ "multisampleRT": "never",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_AYUV":
+ {
+ "texture2D": "11_1",
+ "texture3D": "never",
+ "textureCube": "never",
+ "shaderSample": "11_1",
+ "renderTarget": "11_1",
+ "multisampleRT": "check",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_Y410":
+ {
+ "texture2D": "11_1",
+ "texture3D": "never",
+ "textureCube": "never",
+ "shaderSample": "11_1",
+ "renderTarget": "never",
+ "multisampleRT": "never",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_Y416":
+ {
+ "texture2D": "11_1",
+ "texture3D": "never",
+ "textureCube": "never",
+ "shaderSample": "11_1",
+ "renderTarget": "never",
+ "multisampleRT": "never",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_NV12":
+ {
+ "texture2D": "11_1",
+ "texture3D": "never",
+ "textureCube": "never",
+ "shaderSample": "11_1",
+ "renderTarget": "11_1",
+ "multisampleRT": "check",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_P010":
+ {
+ "texture2D": "11_1",
+ "texture3D": "never",
+ "textureCube": "never",
+ "shaderSample": "11_1",
+ "renderTarget": "11_1",
+ "multisampleRT": "check",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_P016":
+ {
+ "texture2D": "11_1",
+ "texture3D": "never",
+ "textureCube": "never",
+ "shaderSample": "11_1",
+ "renderTarget": "11_1",
+ "multisampleRT": "check",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_420_OPAQUE":
+ {
+ "texture2D": "11_1",
+ "texture3D": "never",
+ "textureCube": "never",
+ "shaderSample": "never",
+ "renderTarget": "never",
+ "multisampleRT": "never",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_YUY2":
+ {
+ "texture2D": "11_1",
+ "texture3D": "never",
+ "textureCube": "never",
+ "shaderSample": "11_1",
+ "renderTarget": "never",
+ "multisampleRT": "never",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_Y210":
+ {
+ "texture2D": "11_1",
+ "texture3D": "never",
+ "textureCube": "never",
+ "shaderSample": "11_1",
+ "renderTarget": "never",
+ "multisampleRT": "never",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_Y216":
+ {
+ "texture2D": "11_1",
+ "texture3D": "never",
+ "textureCube": "never",
+ "shaderSample": "11_1",
+ "renderTarget": "never",
+ "multisampleRT": "never",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_NV11":
+ {
+ "texture2D": "11_1",
+ "texture3D": "never",
+ "textureCube": "never",
+ "shaderSample": "11_1",
+ "renderTarget": "11_1",
+ "multisampleRT": "check",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_AI44":
+ {
+ "texture2D": "11_1",
+ "texture3D": "never",
+ "textureCube": "never",
+ "shaderSample": "never",
+ "renderTarget": "never",
+ "multisampleRT": "never",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_IA44":
+ {
+ "texture2D": "11_1",
+ "texture3D": "never",
+ "textureCube": "never",
+ "shaderSample": "never",
+ "renderTarget": "never",
+ "multisampleRT": "never",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_P8":
+ {
+ "texture2D": "11_1",
+ "texture3D": "never",
+ "textureCube": "never",
+ "shaderSample": "never",
+ "renderTarget": "never",
+ "multisampleRT": "never",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_A8P8":
+ {
+ "texture2D": "11_1",
+ "texture3D": "never",
+ "textureCube": "never",
+ "shaderSample": "never",
+ "renderTarget": "never",
+ "multisampleRT": "never",
+ "depthStencil": "never"
+ },
+ "DXGI_FORMAT_B4G4R4A4_UNORM":
+ {
+ "texture2D": "dxgi1_2",
+ "texture3D": "dxgi1_2",
+ "textureCube": "dxgi1_2",
+ "shaderSample": "dxgi1_2",
+ "renderTarget": "check",
+ "multisampleRT": "check",
+ "depthStencil": "never"
+ }
+ }
+]
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/dxgi_support_table.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/dxgi_support_table.cpp
new file mode 100644
index 0000000000..cbc36445e6
--- /dev/null
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/dxgi_support_table.cpp
@@ -0,0 +1,1846 @@
+// GENERATED FILE - DO NOT EDIT. See dxgi_support_data.json.
+//
+// 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.
+//
+// dxgi_support_table:
+// Queries for DXGI support of various texture formats. Depends on DXGI
+// version, D3D feature level, and is sometimes guaranteed or optional.
+//
+
+#include "libANGLE/renderer/d3d/d3d11/dxgi_support_table.h"
+
+#include "common/debug.h"
+
+namespace rx
+{
+
+namespace d3d11
+{
+
+#define F_2D D3D11_FORMAT_SUPPORT_TEXTURE2D
+#define F_3D D3D11_FORMAT_SUPPORT_TEXTURE3D
+#define F_CUBE D3D11_FORMAT_SUPPORT_TEXTURECUBE
+#define F_SAMPLE D3D11_FORMAT_SUPPORT_SHADER_SAMPLE
+#define F_RT D3D11_FORMAT_SUPPORT_RENDER_TARGET
+#define F_MS D3D11_FORMAT_SUPPORT_MULTISAMPLE_RENDERTARGET
+#define F_DS D3D11_FORMAT_SUPPORT_DEPTH_STENCIL
+
+namespace
+{
+
+const DXGISupport &GetDefaultSupport()
+{
+ static UINT AllSupportFlags = D3D11_FORMAT_SUPPORT_TEXTURE2D |
+ D3D11_FORMAT_SUPPORT_TEXTURE3D |
+ D3D11_FORMAT_SUPPORT_TEXTURECUBE |
+ D3D11_FORMAT_SUPPORT_SHADER_SAMPLE |
+ D3D11_FORMAT_SUPPORT_RENDER_TARGET |
+ D3D11_FORMAT_SUPPORT_MULTISAMPLE_RENDERTARGET |
+ D3D11_FORMAT_SUPPORT_DEPTH_STENCIL;
+ static const DXGISupport defaultSupport(0, 0, AllSupportFlags);
+ return defaultSupport;
+}
+
+const DXGISupport &GetDXGISupport_10_0(DXGI_FORMAT dxgiFormat)
+{
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_420_OPAQUE:
+ {
+ static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_A8P8:
+ {
+ static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_A8_UNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_AI44:
+ {
+ static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_AYUV:
+ {
+ static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_RT | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_B4G4R4A4_UNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS, F_MS | F_RT);
+ return info;
+ }
+ case DXGI_FORMAT_B5G5R5A1_UNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS, F_MS | F_RT);
+ return info;
+ }
+ case DXGI_FORMAT_B5G6R5_UNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_B8G8R8A8_TYPELESS:
+ {
+ static const DXGISupport info(0, F_DS | F_MS | F_RT | F_SAMPLE, F_2D | F_3D | F_CUBE);
+ return info;
+ }
+ case DXGI_FORMAT_B8G8R8A8_UNORM:
+ {
+ static const DXGISupport info(0, F_DS, F_2D | F_3D | F_CUBE | F_MS | F_RT | F_SAMPLE);
+ return info;
+ }
+ case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
+ {
+ static const DXGISupport info(0, F_DS, F_2D | F_3D | F_CUBE | F_MS | F_SAMPLE);
+ return info;
+ }
+ case DXGI_FORMAT_B8G8R8X8_TYPELESS:
+ {
+ static const DXGISupport info(0, F_DS | F_MS | F_RT | F_SAMPLE, F_2D | F_3D | F_CUBE);
+ return info;
+ }
+ case DXGI_FORMAT_B8G8R8X8_UNORM:
+ {
+ static const DXGISupport info(0, F_DS, F_2D | F_3D | F_CUBE | F_MS | F_SAMPLE);
+ return info;
+ }
+ case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:
+ {
+ static const DXGISupport info(0, F_DS, F_2D | F_3D | F_CUBE | F_MS | F_SAMPLE);
+ return info;
+ }
+ case DXGI_FORMAT_BC1_TYPELESS:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_BC1_UNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0);
+ return info;
+ }
+ case DXGI_FORMAT_BC1_UNORM_SRGB:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0);
+ return info;
+ }
+ case DXGI_FORMAT_BC2_TYPELESS:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_BC2_UNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0);
+ return info;
+ }
+ case DXGI_FORMAT_BC2_UNORM_SRGB:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0);
+ return info;
+ }
+ case DXGI_FORMAT_BC3_TYPELESS:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_BC3_UNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0);
+ return info;
+ }
+ case DXGI_FORMAT_BC3_UNORM_SRGB:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0);
+ return info;
+ }
+ case DXGI_FORMAT_BC4_SNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0);
+ return info;
+ }
+ case DXGI_FORMAT_BC4_TYPELESS:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_BC4_UNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0);
+ return info;
+ }
+ case DXGI_FORMAT_BC5_SNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0);
+ return info;
+ }
+ case DXGI_FORMAT_BC5_TYPELESS:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_BC5_UNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0);
+ return info;
+ }
+ case DXGI_FORMAT_BC6H_SF16:
+ {
+ static const DXGISupport info(0, F_DS | F_MS | F_RT, 0);
+ return info;
+ }
+ case DXGI_FORMAT_BC6H_TYPELESS:
+ {
+ static const DXGISupport info(0, F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_BC6H_UF16:
+ {
+ static const DXGISupport info(0, F_DS | F_MS | F_RT, 0);
+ return info;
+ }
+ case DXGI_FORMAT_BC7_TYPELESS:
+ {
+ static const DXGISupport info(0, F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_BC7_UNORM:
+ {
+ static const DXGISupport info(0, F_DS | F_MS | F_RT, 0);
+ return info;
+ }
+ case DXGI_FORMAT_BC7_UNORM_SRGB:
+ {
+ static const DXGISupport info(0, F_DS | F_MS | F_RT, 0);
+ return info;
+ }
+ case DXGI_FORMAT_D16_UNORM:
+ {
+ static const DXGISupport info(F_2D | F_CUBE | F_DS, F_3D | F_RT | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_D24_UNORM_S8_UINT:
+ {
+ static const DXGISupport info(F_2D | F_CUBE | F_DS, F_3D | F_RT | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_D32_FLOAT:
+ {
+ static const DXGISupport info(F_2D | F_CUBE | F_DS, F_3D | F_RT | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_D32_FLOAT_S8X24_UINT:
+ {
+ static const DXGISupport info(F_2D | F_CUBE | F_DS, F_3D | F_RT | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_G8R8_G8B8_UNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0);
+ return info;
+ }
+ case DXGI_FORMAT_IA44:
+ {
+ static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_NV11:
+ {
+ static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_RT | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_NV12:
+ {
+ static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_RT | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_P010:
+ {
+ static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_RT | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_P016:
+ {
+ static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_RT | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_P8:
+ {
+ static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_R10G10B10A2_TYPELESS:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_R10G10B10A2_UINT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R10G10B10A2_UNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM:
+ {
+ static const DXGISupport info(0, F_CUBE | F_DS | F_MS | F_RT | F_SAMPLE, F_2D | F_3D);
+ return info;
+ }
+ case DXGI_FORMAT_R11G11B10_FLOAT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R16G16B16A16_FLOAT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R16G16B16A16_SINT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R16G16B16A16_SNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R16G16B16A16_TYPELESS:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_R16G16B16A16_UINT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R16G16B16A16_UNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R16G16_FLOAT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R16G16_SINT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R16G16_SNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R16G16_TYPELESS:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_R16G16_UINT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R16G16_UNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R16_FLOAT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R16_SINT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R16_SNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R16_TYPELESS:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_R16_UINT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R16_UNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R1_UNORM:
+ {
+ static const DXGISupport info(F_2D, F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_R24G8_TYPELESS:
+ {
+ static const DXGISupport info(F_2D | F_CUBE, F_3D | F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_R24_UNORM_X8_TYPELESS:
+ {
+ static const DXGISupport info(F_2D | F_CUBE, F_3D | F_DS | F_MS | F_RT, F_SAMPLE);
+ return info;
+ }
+ case DXGI_FORMAT_R32G32B32A32_FLOAT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS, F_MS | F_SAMPLE);
+ return info;
+ }
+ case DXGI_FORMAT_R32G32B32A32_SINT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R32G32B32A32_TYPELESS:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_R32G32B32A32_UINT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R32G32B32_FLOAT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS, F_MS | F_RT);
+ return info;
+ }
+ case DXGI_FORMAT_R32G32B32_SINT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_SAMPLE, F_MS | F_RT);
+ return info;
+ }
+ case DXGI_FORMAT_R32G32B32_TYPELESS:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_R32G32B32_UINT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_SAMPLE, F_MS | F_RT);
+ return info;
+ }
+ case DXGI_FORMAT_R32G32_FLOAT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS, F_MS | F_SAMPLE);
+ return info;
+ }
+ case DXGI_FORMAT_R32G32_SINT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R32G32_TYPELESS:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_R32G32_UINT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R32G8X24_TYPELESS:
+ {
+ static const DXGISupport info(F_2D | F_CUBE, F_3D | F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_R32_FLOAT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS, F_MS | F_SAMPLE);
+ return info;
+ }
+ case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS:
+ {
+ static const DXGISupport info(F_2D | F_CUBE, F_3D | F_DS | F_MS | F_RT, F_SAMPLE);
+ return info;
+ }
+ case DXGI_FORMAT_R32_SINT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R32_TYPELESS:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_R32_UINT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R8G8B8A8_SINT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R8G8B8A8_SNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R8G8B8A8_TYPELESS:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_R8G8B8A8_UINT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R8G8B8A8_UNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R8G8_B8G8_UNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0);
+ return info;
+ }
+ case DXGI_FORMAT_R8G8_SINT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R8G8_SNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R8G8_TYPELESS:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_R8G8_UINT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R8G8_UNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R8_SINT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R8_SNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R8_TYPELESS:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_R8_UINT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R8_UNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R9G9B9E5_SHAREDEXP:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0);
+ return info;
+ }
+ case DXGI_FORMAT_UNKNOWN:
+ {
+ static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_X24_TYPELESS_G8_UINT:
+ {
+ static const DXGISupport info(F_2D | F_CUBE, F_3D | F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT:
+ {
+ static const DXGISupport info(F_2D | F_CUBE, F_3D | F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_Y210:
+ {
+ static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_Y216:
+ {
+ static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_Y410:
+ {
+ static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_Y416:
+ {
+ static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_YUY2:
+ {
+ static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+
+ default:
+ UNREACHABLE();
+ return GetDefaultSupport();
+ }
+}
+
+const DXGISupport &GetDXGISupport_10_1(DXGI_FORMAT dxgiFormat)
+{
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_420_OPAQUE:
+ {
+ static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_A8P8:
+ {
+ static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_A8_UNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_AI44:
+ {
+ static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_AYUV:
+ {
+ static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_RT | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_B4G4R4A4_UNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS, F_MS | F_RT);
+ return info;
+ }
+ case DXGI_FORMAT_B5G5R5A1_UNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS, F_MS | F_RT);
+ return info;
+ }
+ case DXGI_FORMAT_B5G6R5_UNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_B8G8R8A8_TYPELESS:
+ {
+ static const DXGISupport info(0, F_DS | F_MS | F_RT | F_SAMPLE, F_2D | F_3D | F_CUBE);
+ return info;
+ }
+ case DXGI_FORMAT_B8G8R8A8_UNORM:
+ {
+ static const DXGISupport info(0, F_DS, F_2D | F_3D | F_CUBE | F_MS | F_RT | F_SAMPLE);
+ return info;
+ }
+ case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
+ {
+ static const DXGISupport info(0, F_DS, F_2D | F_3D | F_CUBE | F_MS | F_SAMPLE);
+ return info;
+ }
+ case DXGI_FORMAT_B8G8R8X8_TYPELESS:
+ {
+ static const DXGISupport info(0, F_DS | F_MS | F_RT | F_SAMPLE, F_2D | F_3D | F_CUBE);
+ return info;
+ }
+ case DXGI_FORMAT_B8G8R8X8_UNORM:
+ {
+ static const DXGISupport info(0, F_DS, F_2D | F_3D | F_CUBE | F_MS | F_SAMPLE);
+ return info;
+ }
+ case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:
+ {
+ static const DXGISupport info(0, F_DS, F_2D | F_3D | F_CUBE | F_MS | F_SAMPLE);
+ return info;
+ }
+ case DXGI_FORMAT_BC1_TYPELESS:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_BC1_UNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0);
+ return info;
+ }
+ case DXGI_FORMAT_BC1_UNORM_SRGB:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0);
+ return info;
+ }
+ case DXGI_FORMAT_BC2_TYPELESS:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_BC2_UNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0);
+ return info;
+ }
+ case DXGI_FORMAT_BC2_UNORM_SRGB:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0);
+ return info;
+ }
+ case DXGI_FORMAT_BC3_TYPELESS:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_BC3_UNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0);
+ return info;
+ }
+ case DXGI_FORMAT_BC3_UNORM_SRGB:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0);
+ return info;
+ }
+ case DXGI_FORMAT_BC4_SNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0);
+ return info;
+ }
+ case DXGI_FORMAT_BC4_TYPELESS:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_BC4_UNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0);
+ return info;
+ }
+ case DXGI_FORMAT_BC5_SNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0);
+ return info;
+ }
+ case DXGI_FORMAT_BC5_TYPELESS:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_BC5_UNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0);
+ return info;
+ }
+ case DXGI_FORMAT_BC6H_SF16:
+ {
+ static const DXGISupport info(0, F_DS | F_MS | F_RT, 0);
+ return info;
+ }
+ case DXGI_FORMAT_BC6H_TYPELESS:
+ {
+ static const DXGISupport info(0, F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_BC6H_UF16:
+ {
+ static const DXGISupport info(0, F_DS | F_MS | F_RT, 0);
+ return info;
+ }
+ case DXGI_FORMAT_BC7_TYPELESS:
+ {
+ static const DXGISupport info(0, F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_BC7_UNORM:
+ {
+ static const DXGISupport info(0, F_DS | F_MS | F_RT, 0);
+ return info;
+ }
+ case DXGI_FORMAT_BC7_UNORM_SRGB:
+ {
+ static const DXGISupport info(0, F_DS | F_MS | F_RT, 0);
+ return info;
+ }
+ case DXGI_FORMAT_D16_UNORM:
+ {
+ static const DXGISupport info(F_2D | F_CUBE | F_DS, F_3D | F_RT | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_D24_UNORM_S8_UINT:
+ {
+ static const DXGISupport info(F_2D | F_CUBE | F_DS, F_3D | F_RT | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_D32_FLOAT:
+ {
+ static const DXGISupport info(F_2D | F_CUBE | F_DS, F_3D | F_RT | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_D32_FLOAT_S8X24_UINT:
+ {
+ static const DXGISupport info(F_2D | F_CUBE | F_DS, F_3D | F_RT | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_G8R8_G8B8_UNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0);
+ return info;
+ }
+ case DXGI_FORMAT_IA44:
+ {
+ static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_NV11:
+ {
+ static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_RT | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_NV12:
+ {
+ static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_RT | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_P010:
+ {
+ static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_RT | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_P016:
+ {
+ static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_RT | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_P8:
+ {
+ static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_R10G10B10A2_TYPELESS:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_R10G10B10A2_UINT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R10G10B10A2_UNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM:
+ {
+ static const DXGISupport info(0, F_CUBE | F_DS | F_MS | F_RT | F_SAMPLE, F_2D | F_3D);
+ return info;
+ }
+ case DXGI_FORMAT_R11G11B10_FLOAT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R16G16B16A16_FLOAT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R16G16B16A16_SINT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R16G16B16A16_SNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R16G16B16A16_TYPELESS:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_R16G16B16A16_UINT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R16G16B16A16_UNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R16G16_FLOAT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R16G16_SINT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R16G16_SNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R16G16_TYPELESS:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_R16G16_UINT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R16G16_UNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R16_FLOAT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R16_SINT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R16_SNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R16_TYPELESS:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_R16_UINT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R16_UNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R1_UNORM:
+ {
+ static const DXGISupport info(F_2D, F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_R24G8_TYPELESS:
+ {
+ static const DXGISupport info(F_2D | F_CUBE, F_3D | F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_R24_UNORM_X8_TYPELESS:
+ {
+ static const DXGISupport info(F_2D | F_CUBE | F_SAMPLE, F_3D | F_DS | F_MS | F_RT, 0);
+ return info;
+ }
+ case DXGI_FORMAT_R32G32B32A32_FLOAT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R32G32B32A32_SINT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R32G32B32A32_TYPELESS:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_R32G32B32A32_UINT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R32G32B32_FLOAT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS, F_MS | F_RT);
+ return info;
+ }
+ case DXGI_FORMAT_R32G32B32_SINT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_SAMPLE, F_MS | F_RT);
+ return info;
+ }
+ case DXGI_FORMAT_R32G32B32_TYPELESS:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_R32G32B32_UINT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_SAMPLE, F_MS | F_RT);
+ return info;
+ }
+ case DXGI_FORMAT_R32G32_FLOAT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R32G32_SINT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R32G32_TYPELESS:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_R32G32_UINT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R32G8X24_TYPELESS:
+ {
+ static const DXGISupport info(F_2D | F_CUBE, F_3D | F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_R32_FLOAT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS:
+ {
+ static const DXGISupport info(F_2D | F_CUBE | F_SAMPLE, F_3D | F_DS | F_MS | F_RT, 0);
+ return info;
+ }
+ case DXGI_FORMAT_R32_SINT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R32_TYPELESS:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_R32_UINT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R8G8B8A8_SINT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R8G8B8A8_SNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R8G8B8A8_TYPELESS:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_R8G8B8A8_UINT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R8G8B8A8_UNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R8G8_B8G8_UNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0);
+ return info;
+ }
+ case DXGI_FORMAT_R8G8_SINT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R8G8_SNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R8G8_TYPELESS:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_R8G8_UINT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R8G8_UNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R8_SINT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R8_SNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R8_TYPELESS:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_R8_UINT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R8_UNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R9G9B9E5_SHAREDEXP:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0);
+ return info;
+ }
+ case DXGI_FORMAT_UNKNOWN:
+ {
+ static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_X24_TYPELESS_G8_UINT:
+ {
+ static const DXGISupport info(F_2D | F_CUBE, F_3D | F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT:
+ {
+ static const DXGISupport info(F_2D | F_CUBE, F_3D | F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_Y210:
+ {
+ static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_Y216:
+ {
+ static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_Y410:
+ {
+ static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_Y416:
+ {
+ static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_YUY2:
+ {
+ static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+
+ default:
+ UNREACHABLE();
+ return GetDefaultSupport();
+ }
+}
+
+const DXGISupport &GetDXGISupport_11_0(DXGI_FORMAT dxgiFormat)
+{
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_420_OPAQUE:
+ {
+ static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_A8P8:
+ {
+ static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_A8_UNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_AI44:
+ {
+ static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_AYUV:
+ {
+ static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_RT | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_B4G4R4A4_UNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS, F_MS | F_RT);
+ return info;
+ }
+ case DXGI_FORMAT_B5G5R5A1_UNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS, F_MS | F_RT);
+ return info;
+ }
+ case DXGI_FORMAT_B5G6R5_UNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_B8G8R8A8_TYPELESS:
+ {
+ static const DXGISupport info(0, F_DS | F_MS | F_RT | F_SAMPLE, F_2D | F_3D | F_CUBE);
+ return info;
+ }
+ case DXGI_FORMAT_B8G8R8A8_UNORM:
+ {
+ static const DXGISupport info(F_RT | F_SAMPLE, F_DS, F_2D | F_3D | F_CUBE | F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
+ {
+ static const DXGISupport info(F_RT | F_SAMPLE, F_DS, F_2D | F_3D | F_CUBE | F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_B8G8R8X8_TYPELESS:
+ {
+ static const DXGISupport info(0, F_DS | F_MS | F_RT | F_SAMPLE, F_2D | F_3D | F_CUBE);
+ return info;
+ }
+ case DXGI_FORMAT_B8G8R8X8_UNORM:
+ {
+ static const DXGISupport info(F_RT | F_SAMPLE, F_DS, F_2D | F_3D | F_CUBE | F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:
+ {
+ static const DXGISupport info(F_RT | F_SAMPLE, F_DS, F_2D | F_3D | F_CUBE | F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_BC1_TYPELESS:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_BC1_UNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0);
+ return info;
+ }
+ case DXGI_FORMAT_BC1_UNORM_SRGB:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0);
+ return info;
+ }
+ case DXGI_FORMAT_BC2_TYPELESS:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_BC2_UNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0);
+ return info;
+ }
+ case DXGI_FORMAT_BC2_UNORM_SRGB:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0);
+ return info;
+ }
+ case DXGI_FORMAT_BC3_TYPELESS:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_BC3_UNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0);
+ return info;
+ }
+ case DXGI_FORMAT_BC3_UNORM_SRGB:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0);
+ return info;
+ }
+ case DXGI_FORMAT_BC4_SNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0);
+ return info;
+ }
+ case DXGI_FORMAT_BC4_TYPELESS:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_BC4_UNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0);
+ return info;
+ }
+ case DXGI_FORMAT_BC5_SNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0);
+ return info;
+ }
+ case DXGI_FORMAT_BC5_TYPELESS:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_BC5_UNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0);
+ return info;
+ }
+ case DXGI_FORMAT_BC6H_SF16:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0);
+ return info;
+ }
+ case DXGI_FORMAT_BC6H_TYPELESS:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_BC6H_UF16:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0);
+ return info;
+ }
+ case DXGI_FORMAT_BC7_TYPELESS:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_BC7_UNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0);
+ return info;
+ }
+ case DXGI_FORMAT_BC7_UNORM_SRGB:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0);
+ return info;
+ }
+ case DXGI_FORMAT_D16_UNORM:
+ {
+ static const DXGISupport info(F_2D | F_CUBE | F_DS, F_3D | F_RT | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_D24_UNORM_S8_UINT:
+ {
+ static const DXGISupport info(F_2D | F_CUBE | F_DS, F_3D | F_RT | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_D32_FLOAT:
+ {
+ static const DXGISupport info(F_2D | F_CUBE | F_DS, F_3D | F_RT | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_D32_FLOAT_S8X24_UINT:
+ {
+ static const DXGISupport info(F_2D | F_CUBE | F_DS, F_3D | F_RT | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_G8R8_G8B8_UNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0);
+ return info;
+ }
+ case DXGI_FORMAT_IA44:
+ {
+ static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_NV11:
+ {
+ static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_RT | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_NV12:
+ {
+ static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_RT | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_P010:
+ {
+ static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_RT | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_P016:
+ {
+ static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_RT | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_P8:
+ {
+ static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_R10G10B10A2_TYPELESS:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_R10G10B10A2_UINT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R10G10B10A2_UNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM:
+ {
+ static const DXGISupport info(0, F_CUBE | F_DS | F_MS | F_RT | F_SAMPLE, F_2D | F_3D);
+ return info;
+ }
+ case DXGI_FORMAT_R11G11B10_FLOAT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R16G16B16A16_FLOAT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R16G16B16A16_SINT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R16G16B16A16_SNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R16G16B16A16_TYPELESS:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_R16G16B16A16_UINT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R16G16B16A16_UNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R16G16_FLOAT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R16G16_SINT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R16G16_SNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R16G16_TYPELESS:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_R16G16_UINT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R16G16_UNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R16_FLOAT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R16_SINT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R16_SNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R16_TYPELESS:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_R16_UINT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R16_UNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R1_UNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_R24G8_TYPELESS:
+ {
+ static const DXGISupport info(F_2D | F_CUBE, F_3D | F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_R24_UNORM_X8_TYPELESS:
+ {
+ static const DXGISupport info(F_2D | F_CUBE | F_SAMPLE, F_3D | F_DS | F_MS | F_RT, 0);
+ return info;
+ }
+ case DXGI_FORMAT_R32G32B32A32_FLOAT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R32G32B32A32_SINT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R32G32B32A32_TYPELESS:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_R32G32B32A32_UINT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R32G32B32_FLOAT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS, F_MS | F_RT);
+ return info;
+ }
+ case DXGI_FORMAT_R32G32B32_SINT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_SAMPLE, F_MS | F_RT);
+ return info;
+ }
+ case DXGI_FORMAT_R32G32B32_TYPELESS:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_R32G32B32_UINT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_SAMPLE, F_MS | F_RT);
+ return info;
+ }
+ case DXGI_FORMAT_R32G32_FLOAT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R32G32_SINT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R32G32_TYPELESS:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_R32G32_UINT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R32G8X24_TYPELESS:
+ {
+ static const DXGISupport info(F_2D | F_CUBE, F_3D | F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_R32_FLOAT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS:
+ {
+ static const DXGISupport info(F_2D | F_CUBE | F_SAMPLE, F_3D | F_DS | F_MS | F_RT, 0);
+ return info;
+ }
+ case DXGI_FORMAT_R32_SINT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R32_TYPELESS:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_R32_UINT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R8G8B8A8_SINT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R8G8B8A8_SNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R8G8B8A8_TYPELESS:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_R8G8B8A8_UINT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R8G8B8A8_UNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R8G8_B8G8_UNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0);
+ return info;
+ }
+ case DXGI_FORMAT_R8G8_SINT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R8G8_SNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R8G8_TYPELESS:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_R8G8_UINT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R8G8_UNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R8_SINT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R8_SNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R8_TYPELESS:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_R8_UINT:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_SAMPLE, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R8_UNORM:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT | F_SAMPLE, F_DS, F_MS);
+ return info;
+ }
+ case DXGI_FORMAT_R9G9B9E5_SHAREDEXP:
+ {
+ static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MS | F_RT, 0);
+ return info;
+ }
+ case DXGI_FORMAT_UNKNOWN:
+ {
+ static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_X24_TYPELESS_G8_UINT:
+ {
+ static const DXGISupport info(F_2D | F_CUBE, F_3D | F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT:
+ {
+ static const DXGISupport info(F_2D | F_CUBE, F_3D | F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_Y210:
+ {
+ static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_Y216:
+ {
+ static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_Y410:
+ {
+ static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_Y416:
+ {
+ static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+ case DXGI_FORMAT_YUY2:
+ {
+ static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_MS | F_RT | F_SAMPLE, 0);
+ return info;
+ }
+
+ default:
+ UNREACHABLE();
+ return GetDefaultSupport();
+ }
+}
+
+}
+
+#undef F_2D
+#undef F_3D
+#undef F_CUBE
+#undef F_SAMPLE
+#undef F_RT
+#undef F_MS
+#undef F_DS
+
+const DXGISupport &GetDXGISupport(DXGI_FORMAT dxgiFormat, D3D_FEATURE_LEVEL featureLevel)
+{
+ switch (featureLevel)
+ {
+ case D3D_FEATURE_LEVEL_10_0:
+ return GetDXGISupport_10_0(dxgiFormat);
+ case D3D_FEATURE_LEVEL_10_1:
+ return GetDXGISupport_10_1(dxgiFormat);
+ case D3D_FEATURE_LEVEL_11_0:
+ return GetDXGISupport_11_0(dxgiFormat);
+ default:
+ return GetDefaultSupport();
+ }
+}
+
+} // namespace d3d11
+
+} // namespace rx
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/dxgi_support_table.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/dxgi_support_table.h
new file mode 100644
index 0000000000..1d8d68565e
--- /dev/null
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/dxgi_support_table.h
@@ -0,0 +1,44 @@
+//
+// 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.
+//
+// dxgi_support_table:
+// Queries for DXGI support of various texture formats. Depends on DXGI
+// version, D3D feature level, and is sometimes guaranteed or optional.
+//
+
+#include "common/platform.h"
+
+namespace rx
+{
+
+namespace d3d11
+{
+
+struct DXGISupport
+{
+ DXGISupport()
+ : alwaysSupportedFlags(0),
+ neverSupportedFlags(0),
+ optionallySupportedFlags(0)
+ {
+ }
+
+ DXGISupport(UINT alwaysSupportedIn, UINT neverSupportedIn, UINT optionallySupportedIn)
+ : alwaysSupportedFlags(alwaysSupportedIn),
+ neverSupportedFlags(neverSupportedIn),
+ optionallySupportedFlags(optionallySupportedIn)
+ {
+ }
+
+ UINT alwaysSupportedFlags;
+ UINT neverSupportedFlags;
+ UINT optionallySupportedFlags;
+};
+
+const DXGISupport &GetDXGISupport(DXGI_FORMAT dxgiFormat, D3D_FEATURE_LEVEL featureLevel);
+
+} // namespace d3d11
+
+} // namespace rx
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/formatutils11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/formatutils11.cpp
index 2f81d6d608..f073e9f46f 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/formatutils11.cpp
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/formatutils11.cpp
@@ -10,11 +10,13 @@
#include "libANGLE/renderer/d3d/d3d11/formatutils11.h"
#include "libANGLE/formatutils.h"
-#include "libANGLE/renderer/Renderer.h"
#include "libANGLE/renderer/d3d/copyimage.h"
+#include "libANGLE/renderer/d3d/d3d11/copyvertex.h"
+#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h"
+#include "libANGLE/renderer/d3d/d3d11/Renderer11.h"
#include "libANGLE/renderer/d3d/generatemip.h"
#include "libANGLE/renderer/d3d/loadimage.h"
-#include "libANGLE/renderer/d3d/d3d11/copyvertex.h"
+#include "libANGLE/renderer/Renderer.h"
namespace rx
{
@@ -99,6 +101,10 @@ static DXGIToESFormatMap BuildDXGIToESFormatMap()
AddDXGIToESEntry(&map, DXGI_FORMAT_BC2_UNORM, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE);
AddDXGIToESEntry(&map, DXGI_FORMAT_BC3_UNORM, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE);
+ AddDXGIToESEntry(&map, DXGI_FORMAT_B5G6R5_UNORM, GL_RGB565);
+ AddDXGIToESEntry(&map, DXGI_FORMAT_B5G5R5A1_UNORM, GL_RGB5_A1);
+ AddDXGIToESEntry(&map, DXGI_FORMAT_B4G4R4A4_UNORM, GL_RGBA4);
+
return map;
}
@@ -210,6 +216,10 @@ static ColorFormatInfoMap BuildColorFormatInfoMap()
InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R9G9B9E5_SHAREDEXP, 9, 9, 9, 0, 5);
InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R11G11B10_FLOAT, 11, 11, 10, 0, 0);
+ InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_B5G6R5_UNORM, 5, 6, 5, 0, 0);
+ InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_B4G4R4A4_UNORM, 4, 4, 4, 4, 0);
+ InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_B5G5R5A1_UNORM, 5, 5, 5, 1, 0);
+
return map;
}
@@ -278,8 +288,20 @@ DXGIFormat::DXGIFormat()
componentType(GL_NONE),
mipGenerationFunction(NULL),
colorReadFunction(NULL),
- fastCopyFunctions()
+ fastCopyFunctions(),
+ nativeMipmapSupport(NULL)
+{
+}
+
+static bool NeverSupported(D3D_FEATURE_LEVEL)
+{
+ return false;
+}
+
+template <D3D_FEATURE_LEVEL requiredFeatureLevel>
+static bool RequiresFeatureLevel(D3D_FEATURE_LEVEL featureLevel)
{
+ return featureLevel >= requiredFeatureLevel;
}
ColorCopyFunction DXGIFormat::getFastCopyFunction(GLenum format, GLenum type) const
@@ -289,7 +311,7 @@ ColorCopyFunction DXGIFormat::getFastCopyFunction(GLenum format, GLenum type) co
}
void AddDXGIFormat(DXGIFormatInfoMap *map, DXGI_FORMAT dxgiFormat, GLuint pixelBits, GLuint blockWidth, GLuint blockHeight,
- GLenum componentType, MipGenerationFunction mipFunc, ColorReadFunction readFunc)
+ GLenum componentType, MipGenerationFunction mipFunc, ColorReadFunction readFunc, NativeMipmapGenerationSupportFunction nativeMipmapSupport)
{
DXGIFormat info;
info.pixelBytes = pixelBits / 8;
@@ -301,11 +323,11 @@ void AddDXGIFormat(DXGIFormatInfoMap *map, DXGI_FORMAT dxgiFormat, GLuint pixelB
if (colorInfoIter != colorInfoMap.end())
{
const DXGIColorFormatInfo &colorInfo = colorInfoIter->second;
- info.redBits = colorInfo.redBits;
- info.greenBits = colorInfo.greenBits;
- info.blueBits = colorInfo.blueBits;
- info.alphaBits = colorInfo.alphaBits;
- info.sharedBits = colorInfo.sharedBits;
+ info.redBits = static_cast<GLuint>(colorInfo.redBits);
+ info.greenBits = static_cast<GLuint>(colorInfo.greenBits);
+ info.blueBits = static_cast<GLuint>(colorInfo.blueBits);
+ info.alphaBits = static_cast<GLuint>(colorInfo.alphaBits);
+ info.sharedBits = static_cast<GLuint>(colorInfo.sharedBits);
}
static const DepthStencilInfoMap dsInfoMap = BuildDepthStencilInfoMap();
@@ -335,6 +357,8 @@ void AddDXGIFormat(DXGIFormatInfoMap *map, DXGI_FORMAT dxgiFormat, GLuint pixelB
info.fastCopyFunctions.insert(std::make_pair(std::make_pair(i->second.destFormat, i->second.destType), i->second.copyFunction));
}
+ info.nativeMipmapSupport = nativeMipmapSupport;
+
map->insert(std::make_pair(dxgiFormat, info));
}
@@ -343,80 +367,86 @@ static DXGIFormatInfoMap BuildDXGIFormatInfoMap()
{
DXGIFormatInfoMap map;
- // | DXGI format |S |W |H |Component Type | Mip generation function | Color read function
- AddDXGIFormat(&map, DXGI_FORMAT_UNKNOWN, 0, 0, 0, GL_NONE, NULL, NULL);
-
- AddDXGIFormat(&map, DXGI_FORMAT_A8_UNORM, 8, 1, 1, GL_UNSIGNED_NORMALIZED, GenerateMip<A8>, ReadColor<A8, GLfloat>);
- AddDXGIFormat(&map, DXGI_FORMAT_R8_UNORM, 8, 1, 1, GL_UNSIGNED_NORMALIZED, GenerateMip<R8>, ReadColor<R8, GLfloat>);
- AddDXGIFormat(&map, DXGI_FORMAT_R8G8_UNORM, 16, 1, 1, GL_UNSIGNED_NORMALIZED, GenerateMip<R8G8>, ReadColor<R8G8, GLfloat>);
- AddDXGIFormat(&map, DXGI_FORMAT_R8G8B8A8_UNORM, 32, 1, 1, GL_UNSIGNED_NORMALIZED, GenerateMip<R8G8B8A8>, ReadColor<R8G8B8A8, GLfloat>);
- AddDXGIFormat(&map, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, 32, 1, 1, GL_UNSIGNED_NORMALIZED, GenerateMip<R8G8B8A8>, ReadColor<R8G8B8A8, GLfloat>);
- AddDXGIFormat(&map, DXGI_FORMAT_B8G8R8A8_UNORM, 32, 1, 1, GL_UNSIGNED_NORMALIZED, GenerateMip<B8G8R8A8>, ReadColor<B8G8R8A8, GLfloat>);
-
- AddDXGIFormat(&map, DXGI_FORMAT_R8_SNORM, 8, 1, 1, GL_SIGNED_NORMALIZED, GenerateMip<R8S>, ReadColor<R8S, GLfloat>);
- AddDXGIFormat(&map, DXGI_FORMAT_R8G8_SNORM, 16, 1, 1, GL_SIGNED_NORMALIZED, GenerateMip<R8G8S>, ReadColor<R8G8S, GLfloat>);
- AddDXGIFormat(&map, DXGI_FORMAT_R8G8B8A8_SNORM, 32, 1, 1, GL_SIGNED_NORMALIZED, GenerateMip<R8G8B8A8S>, ReadColor<R8G8B8A8S, GLfloat>);
-
- AddDXGIFormat(&map, DXGI_FORMAT_R8_UINT, 8, 1, 1, GL_UNSIGNED_INT, GenerateMip<R8>, ReadColor<R8, GLuint>);
- AddDXGIFormat(&map, DXGI_FORMAT_R16_UINT, 16, 1, 1, GL_UNSIGNED_INT, GenerateMip<R16>, ReadColor<R16, GLuint>);
- AddDXGIFormat(&map, DXGI_FORMAT_R32_UINT, 32, 1, 1, GL_UNSIGNED_INT, GenerateMip<R32>, ReadColor<R32, GLuint>);
- AddDXGIFormat(&map, DXGI_FORMAT_R8G8_UINT, 16, 1, 1, GL_UNSIGNED_INT, GenerateMip<R8G8>, ReadColor<R8G8, GLuint>);
- AddDXGIFormat(&map, DXGI_FORMAT_R16G16_UINT, 32, 1, 1, GL_UNSIGNED_INT, GenerateMip<R16G16>, ReadColor<R16G16, GLuint>);
- AddDXGIFormat(&map, DXGI_FORMAT_R32G32_UINT, 64, 1, 1, GL_UNSIGNED_INT, GenerateMip<R32G32>, ReadColor<R32G32, GLuint>);
- AddDXGIFormat(&map, DXGI_FORMAT_R32G32B32_UINT, 96, 1, 1, GL_UNSIGNED_INT, GenerateMip<R32G32B32>, ReadColor<R32G32B32, GLuint>);
- AddDXGIFormat(&map, DXGI_FORMAT_R8G8B8A8_UINT, 32, 1, 1, GL_UNSIGNED_INT, GenerateMip<R8G8B8A8>, ReadColor<R8G8B8A8, GLuint>);
- AddDXGIFormat(&map, DXGI_FORMAT_R16G16B16A16_UINT, 64, 1, 1, GL_UNSIGNED_INT, GenerateMip<R16G16B16A16>, ReadColor<R16G16B16A16, GLuint>);
- AddDXGIFormat(&map, DXGI_FORMAT_R32G32B32A32_UINT, 128, 1, 1, GL_UNSIGNED_INT, GenerateMip<R32G32B32A32>, ReadColor<R32G32B32A32, GLuint>);
-
- AddDXGIFormat(&map, DXGI_FORMAT_R8_SINT, 8, 1, 1, GL_INT, GenerateMip<R8S>, ReadColor<R8S, GLint>);
- AddDXGIFormat(&map, DXGI_FORMAT_R16_SINT, 16, 1, 1, GL_INT, GenerateMip<R16S>, ReadColor<R16S, GLint>);
- AddDXGIFormat(&map, DXGI_FORMAT_R32_SINT, 32, 1, 1, GL_INT, GenerateMip<R32S>, ReadColor<R32S, GLint>);
- AddDXGIFormat(&map, DXGI_FORMAT_R8G8_SINT, 16, 1, 1, GL_INT, GenerateMip<R8G8S>, ReadColor<R8G8S, GLint>);
- AddDXGIFormat(&map, DXGI_FORMAT_R16G16_SINT, 32, 1, 1, GL_INT, GenerateMip<R16G16S>, ReadColor<R16G16S, GLint>);
- AddDXGIFormat(&map, DXGI_FORMAT_R32G32_SINT, 64, 1, 1, GL_INT, GenerateMip<R32G32S>, ReadColor<R32G32S, GLint>);
- AddDXGIFormat(&map, DXGI_FORMAT_R32G32B32_SINT, 96, 1, 1, GL_INT, GenerateMip<R32G32B32S>, ReadColor<R32G32B32S, GLint>);
- AddDXGIFormat(&map, DXGI_FORMAT_R8G8B8A8_SINT, 32, 1, 1, GL_INT, GenerateMip<R8G8B8A8S>, ReadColor<R8G8B8A8S, GLint>);
- AddDXGIFormat(&map, DXGI_FORMAT_R16G16B16A16_SINT, 64, 1, 1, GL_INT, GenerateMip<R16G16B16A16S>, ReadColor<R16G16B16A16S, GLint>);
- AddDXGIFormat(&map, DXGI_FORMAT_R32G32B32A32_SINT, 128, 1, 1, GL_INT, GenerateMip<R32G32B32A32S>, ReadColor<R32G32B32A32S, GLint>);
-
- AddDXGIFormat(&map, DXGI_FORMAT_R10G10B10A2_UNORM, 32, 1, 1, GL_UNSIGNED_NORMALIZED, GenerateMip<R10G10B10A2>, ReadColor<R10G10B10A2, GLfloat>);
- AddDXGIFormat(&map, DXGI_FORMAT_R10G10B10A2_UINT, 32, 1, 1, GL_UNSIGNED_INT, GenerateMip<R10G10B10A2>, ReadColor<R10G10B10A2, GLuint>);
-
- AddDXGIFormat(&map, DXGI_FORMAT_R16_FLOAT, 16, 1, 1, GL_FLOAT, GenerateMip<R16F>, ReadColor<R16F, GLfloat>);
- AddDXGIFormat(&map, DXGI_FORMAT_R16G16_FLOAT, 32, 1, 1, GL_FLOAT, GenerateMip<R16G16F>, ReadColor<R16G16F, GLfloat>);
- AddDXGIFormat(&map, DXGI_FORMAT_R16G16B16A16_FLOAT, 64, 1, 1, GL_FLOAT, GenerateMip<R16G16B16A16F>, ReadColor<R16G16B16A16F, GLfloat>);
-
- AddDXGIFormat(&map, DXGI_FORMAT_R32_FLOAT, 32, 1, 1, GL_FLOAT, GenerateMip<R32F>, ReadColor<R32F, GLfloat>);
- AddDXGIFormat(&map, DXGI_FORMAT_R32G32_FLOAT, 64, 1, 1, GL_FLOAT, GenerateMip<R32G32F>, ReadColor<R32G32F, GLfloat>);
- AddDXGIFormat(&map, DXGI_FORMAT_R32G32B32_FLOAT, 96, 1, 1, GL_FLOAT, NULL, NULL);
- AddDXGIFormat(&map, DXGI_FORMAT_R32G32B32A32_FLOAT, 128, 1, 1, GL_FLOAT, GenerateMip<R32G32B32A32F>, ReadColor<R32G32B32A32F, GLfloat>);
-
- AddDXGIFormat(&map, DXGI_FORMAT_R9G9B9E5_SHAREDEXP, 32, 1, 1, GL_FLOAT, GenerateMip<R9G9B9E5>, ReadColor<R9G9B9E5, GLfloat>);
- AddDXGIFormat(&map, DXGI_FORMAT_R11G11B10_FLOAT, 32, 1, 1, GL_FLOAT, GenerateMip<R11G11B10F>, ReadColor<R11G11B10F, GLfloat>);
-
- AddDXGIFormat(&map, DXGI_FORMAT_R16_TYPELESS, 16, 1, 1, GL_NONE, NULL, NULL);
- AddDXGIFormat(&map, DXGI_FORMAT_R16_UNORM, 16, 1, 1, GL_UNSIGNED_NORMALIZED, NULL, NULL);
- AddDXGIFormat(&map, DXGI_FORMAT_D16_UNORM, 16, 1, 1, GL_UNSIGNED_NORMALIZED, NULL, NULL);
- AddDXGIFormat(&map, DXGI_FORMAT_R24G8_TYPELESS, 32, 1, 1, GL_NONE, NULL, NULL);
- AddDXGIFormat(&map, DXGI_FORMAT_R24_UNORM_X8_TYPELESS, 32, 1, 1, GL_NONE, NULL, NULL);
- AddDXGIFormat(&map, DXGI_FORMAT_D24_UNORM_S8_UINT, 32, 1, 1, GL_UNSIGNED_INT, NULL, NULL);
- AddDXGIFormat(&map, DXGI_FORMAT_R32G8X24_TYPELESS, 64, 1, 1, GL_NONE, NULL, NULL);
- AddDXGIFormat(&map, DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS, 64, 1, 1, GL_NONE, NULL, NULL);
- AddDXGIFormat(&map, DXGI_FORMAT_D32_FLOAT_S8X24_UINT, 64, 1, 1, GL_UNSIGNED_INT, NULL, NULL);
- AddDXGIFormat(&map, DXGI_FORMAT_R32_TYPELESS, 32, 1, 1, GL_NONE, NULL, NULL);
- AddDXGIFormat(&map, DXGI_FORMAT_D32_FLOAT, 32, 1, 1, GL_FLOAT, NULL, NULL);
-
- AddDXGIFormat(&map, DXGI_FORMAT_BC1_UNORM, 64, 4, 4, GL_UNSIGNED_NORMALIZED, NULL, NULL);
- AddDXGIFormat(&map, DXGI_FORMAT_BC2_UNORM, 128, 4, 4, GL_UNSIGNED_NORMALIZED, NULL, NULL);
- AddDXGIFormat(&map, DXGI_FORMAT_BC3_UNORM, 128, 4, 4, GL_UNSIGNED_NORMALIZED, NULL, NULL);
+ // | DXGI format |S |W |H |Component Type | Mip generation function | Color read function | Native mipmap function
+ AddDXGIFormat(&map, DXGI_FORMAT_UNKNOWN, 0, 0, 0, GL_NONE, NULL, NULL, NeverSupported);
+
+ AddDXGIFormat(&map, DXGI_FORMAT_A8_UNORM, 8, 1, 1, GL_UNSIGNED_NORMALIZED, GenerateMip<A8>, ReadColor<A8, GLfloat>, RequiresFeatureLevel<D3D_FEATURE_LEVEL_10_0>);
+ AddDXGIFormat(&map, DXGI_FORMAT_R8_UNORM, 8, 1, 1, GL_UNSIGNED_NORMALIZED, GenerateMip<R8>, ReadColor<R8, GLfloat>, RequiresFeatureLevel<D3D_FEATURE_LEVEL_10_0>);
+ AddDXGIFormat(&map, DXGI_FORMAT_R8G8_UNORM, 16, 1, 1, GL_UNSIGNED_NORMALIZED, GenerateMip<R8G8>, ReadColor<R8G8, GLfloat>, RequiresFeatureLevel<D3D_FEATURE_LEVEL_10_0>);
+ AddDXGIFormat(&map, DXGI_FORMAT_R8G8B8A8_UNORM, 32, 1, 1, GL_UNSIGNED_NORMALIZED, GenerateMip<R8G8B8A8>, ReadColor<R8G8B8A8, GLfloat>, RequiresFeatureLevel<D3D_FEATURE_LEVEL_9_1>);
+ AddDXGIFormat(&map, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, 32, 1, 1, GL_UNSIGNED_NORMALIZED, GenerateMip<R8G8B8A8>, ReadColor<R8G8B8A8, GLfloat>, RequiresFeatureLevel<D3D_FEATURE_LEVEL_9_1>);
+ AddDXGIFormat(&map, DXGI_FORMAT_B8G8R8A8_UNORM, 32, 1, 1, GL_UNSIGNED_NORMALIZED, GenerateMip<B8G8R8A8>, ReadColor<B8G8R8A8, GLfloat>, RequiresFeatureLevel<D3D_FEATURE_LEVEL_9_1>);
+
+ AddDXGIFormat(&map, DXGI_FORMAT_R8_SNORM, 8, 1, 1, GL_SIGNED_NORMALIZED, GenerateMip<R8S>, ReadColor<R8S, GLfloat> , RequiresFeatureLevel<D3D_FEATURE_LEVEL_10_0>);
+ AddDXGIFormat(&map, DXGI_FORMAT_R8G8_SNORM, 16, 1, 1, GL_SIGNED_NORMALIZED, GenerateMip<R8G8S>, ReadColor<R8G8S, GLfloat> , RequiresFeatureLevel<D3D_FEATURE_LEVEL_10_0>);
+ AddDXGIFormat(&map, DXGI_FORMAT_R8G8B8A8_SNORM, 32, 1, 1, GL_SIGNED_NORMALIZED, GenerateMip<R8G8B8A8S>, ReadColor<R8G8B8A8S, GLfloat>, RequiresFeatureLevel<D3D_FEATURE_LEVEL_10_0>);
+
+ AddDXGIFormat(&map, DXGI_FORMAT_R8_UINT, 8, 1, 1, GL_UNSIGNED_INT, GenerateMip<R8>, ReadColor<R8, GLuint>, NeverSupported);
+ AddDXGIFormat(&map, DXGI_FORMAT_R16_UINT, 16, 1, 1, GL_UNSIGNED_INT, GenerateMip<R16>, ReadColor<R16, GLuint>, NeverSupported);
+ AddDXGIFormat(&map, DXGI_FORMAT_R32_UINT, 32, 1, 1, GL_UNSIGNED_INT, GenerateMip<R32>, ReadColor<R32, GLuint>, NeverSupported);
+ AddDXGIFormat(&map, DXGI_FORMAT_R8G8_UINT, 16, 1, 1, GL_UNSIGNED_INT, GenerateMip<R8G8>, ReadColor<R8G8, GLuint>, NeverSupported);
+ AddDXGIFormat(&map, DXGI_FORMAT_R16G16_UINT, 32, 1, 1, GL_UNSIGNED_INT, GenerateMip<R16G16>, ReadColor<R16G16, GLuint>, NeverSupported);
+ AddDXGIFormat(&map, DXGI_FORMAT_R32G32_UINT, 64, 1, 1, GL_UNSIGNED_INT, GenerateMip<R32G32>, ReadColor<R32G32, GLuint>, NeverSupported);
+ AddDXGIFormat(&map, DXGI_FORMAT_R32G32B32_UINT, 96, 1, 1, GL_UNSIGNED_INT, GenerateMip<R32G32B32>, ReadColor<R32G32B32, GLuint>, NeverSupported);
+ AddDXGIFormat(&map, DXGI_FORMAT_R8G8B8A8_UINT, 32, 1, 1, GL_UNSIGNED_INT, GenerateMip<R8G8B8A8>, ReadColor<R8G8B8A8, GLuint>, NeverSupported);
+ AddDXGIFormat(&map, DXGI_FORMAT_R16G16B16A16_UINT, 64, 1, 1, GL_UNSIGNED_INT, GenerateMip<R16G16B16A16>, ReadColor<R16G16B16A16, GLuint>, NeverSupported);
+ AddDXGIFormat(&map, DXGI_FORMAT_R32G32B32A32_UINT, 128, 1, 1, GL_UNSIGNED_INT, GenerateMip<R32G32B32A32>, ReadColor<R32G32B32A32, GLuint>, NeverSupported);
+
+ AddDXGIFormat(&map, DXGI_FORMAT_R8_SINT, 8, 1, 1, GL_INT, GenerateMip<R8S>, ReadColor<R8S, GLint>, NeverSupported);
+ AddDXGIFormat(&map, DXGI_FORMAT_R16_SINT, 16, 1, 1, GL_INT, GenerateMip<R16S>, ReadColor<R16S, GLint>, NeverSupported);
+ AddDXGIFormat(&map, DXGI_FORMAT_R32_SINT, 32, 1, 1, GL_INT, GenerateMip<R32S>, ReadColor<R32S, GLint>, NeverSupported);
+ AddDXGIFormat(&map, DXGI_FORMAT_R8G8_SINT, 16, 1, 1, GL_INT, GenerateMip<R8G8S>, ReadColor<R8G8S, GLint>, NeverSupported);
+ AddDXGIFormat(&map, DXGI_FORMAT_R16G16_SINT, 32, 1, 1, GL_INT, GenerateMip<R16G16S>, ReadColor<R16G16S, GLint>, NeverSupported);
+ AddDXGIFormat(&map, DXGI_FORMAT_R32G32_SINT, 64, 1, 1, GL_INT, GenerateMip<R32G32S>, ReadColor<R32G32S, GLint>, NeverSupported);
+ AddDXGIFormat(&map, DXGI_FORMAT_R32G32B32_SINT, 96, 1, 1, GL_INT, GenerateMip<R32G32B32S>, ReadColor<R32G32B32S, GLint>, NeverSupported);
+ AddDXGIFormat(&map, DXGI_FORMAT_R8G8B8A8_SINT, 32, 1, 1, GL_INT, GenerateMip<R8G8B8A8S>, ReadColor<R8G8B8A8S, GLint>, NeverSupported);
+ AddDXGIFormat(&map, DXGI_FORMAT_R16G16B16A16_SINT, 64, 1, 1, GL_INT, GenerateMip<R16G16B16A16S>, ReadColor<R16G16B16A16S, GLint>, NeverSupported);
+ AddDXGIFormat(&map, DXGI_FORMAT_R32G32B32A32_SINT, 128, 1, 1, GL_INT, GenerateMip<R32G32B32A32S>, ReadColor<R32G32B32A32S, GLint>, NeverSupported);
+
+ AddDXGIFormat(&map, DXGI_FORMAT_R10G10B10A2_UNORM, 32, 1, 1, GL_UNSIGNED_NORMALIZED, GenerateMip<R10G10B10A2>, ReadColor<R10G10B10A2, GLfloat>, RequiresFeatureLevel<D3D_FEATURE_LEVEL_10_0>);
+ AddDXGIFormat(&map, DXGI_FORMAT_R10G10B10A2_UINT, 32, 1, 1, GL_UNSIGNED_INT, GenerateMip<R10G10B10A2>, ReadColor<R10G10B10A2, GLuint>, NeverSupported);
+
+ AddDXGIFormat(&map, DXGI_FORMAT_R16_FLOAT, 16, 1, 1, GL_FLOAT, GenerateMip<R16F>, ReadColor<R16F, GLfloat>, RequiresFeatureLevel<D3D_FEATURE_LEVEL_10_0>);
+ AddDXGIFormat(&map, DXGI_FORMAT_R16G16_FLOAT, 32, 1, 1, GL_FLOAT, GenerateMip<R16G16F>, ReadColor<R16G16F, GLfloat>, RequiresFeatureLevel<D3D_FEATURE_LEVEL_9_2>);
+ AddDXGIFormat(&map, DXGI_FORMAT_R16G16B16A16_FLOAT, 64, 1, 1, GL_FLOAT, GenerateMip<R16G16B16A16F>, ReadColor<R16G16B16A16F, GLfloat>, RequiresFeatureLevel<D3D_FEATURE_LEVEL_9_2>);
+
+ AddDXGIFormat(&map, DXGI_FORMAT_R32_FLOAT, 32, 1, 1, GL_FLOAT, GenerateMip<R32F>, ReadColor<R32F, GLfloat>, RequiresFeatureLevel<D3D_FEATURE_LEVEL_9_2>);
+ AddDXGIFormat(&map, DXGI_FORMAT_R32G32_FLOAT, 64, 1, 1, GL_FLOAT, GenerateMip<R32G32F>, ReadColor<R32G32F, GLfloat>, RequiresFeatureLevel<D3D_FEATURE_LEVEL_10_0>);
+ AddDXGIFormat(&map, DXGI_FORMAT_R32G32B32_FLOAT, 96, 1, 1, GL_FLOAT, NULL, NULL, NeverSupported);
+ AddDXGIFormat(&map, DXGI_FORMAT_R32G32B32A32_FLOAT, 128, 1, 1, GL_FLOAT, GenerateMip<R32G32B32A32F>, ReadColor<R32G32B32A32F, GLfloat>, RequiresFeatureLevel<D3D_FEATURE_LEVEL_9_3>);
+
+ AddDXGIFormat(&map, DXGI_FORMAT_R9G9B9E5_SHAREDEXP, 32, 1, 1, GL_FLOAT, GenerateMip<R9G9B9E5>, ReadColor<R9G9B9E5, GLfloat>, NeverSupported);
+ AddDXGIFormat(&map, DXGI_FORMAT_R11G11B10_FLOAT, 32, 1, 1, GL_FLOAT, GenerateMip<R11G11B10F>, ReadColor<R11G11B10F, GLfloat>, RequiresFeatureLevel<D3D_FEATURE_LEVEL_10_0>);
+
+ AddDXGIFormat(&map, DXGI_FORMAT_R16_TYPELESS, 16, 1, 1, GL_NONE, NULL, NULL, NeverSupported);
+ AddDXGIFormat(&map, DXGI_FORMAT_R16_UNORM, 16, 1, 1, GL_UNSIGNED_NORMALIZED, NULL, NULL, NeverSupported);
+ AddDXGIFormat(&map, DXGI_FORMAT_D16_UNORM, 16, 1, 1, GL_UNSIGNED_NORMALIZED, NULL, NULL, NeverSupported);
+ AddDXGIFormat(&map, DXGI_FORMAT_R24G8_TYPELESS, 32, 1, 1, GL_NONE, NULL, NULL, NeverSupported);
+ AddDXGIFormat(&map, DXGI_FORMAT_R24_UNORM_X8_TYPELESS, 32, 1, 1, GL_NONE, NULL, NULL, NeverSupported);
+ AddDXGIFormat(&map, DXGI_FORMAT_D24_UNORM_S8_UINT, 32, 1, 1, GL_UNSIGNED_INT, NULL, NULL, NeverSupported);
+ AddDXGIFormat(&map, DXGI_FORMAT_R32G8X24_TYPELESS, 64, 1, 1, GL_NONE, NULL, NULL, NeverSupported);
+ AddDXGIFormat(&map, DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS, 64, 1, 1, GL_NONE, NULL, NULL, NeverSupported);
+ AddDXGIFormat(&map, DXGI_FORMAT_D32_FLOAT_S8X24_UINT, 64, 1, 1, GL_UNSIGNED_INT, NULL, NULL, NeverSupported);
+ AddDXGIFormat(&map, DXGI_FORMAT_R32_TYPELESS, 32, 1, 1, GL_NONE, NULL, NULL, NeverSupported);
+ AddDXGIFormat(&map, DXGI_FORMAT_D32_FLOAT, 32, 1, 1, GL_FLOAT, NULL, NULL, NeverSupported);
+
+ AddDXGIFormat(&map, DXGI_FORMAT_BC1_UNORM, 64, 4, 4, GL_UNSIGNED_NORMALIZED, NULL, NULL, NeverSupported);
+ AddDXGIFormat(&map, DXGI_FORMAT_BC2_UNORM, 128, 4, 4, GL_UNSIGNED_NORMALIZED, NULL, NULL, NeverSupported);
+ AddDXGIFormat(&map, DXGI_FORMAT_BC3_UNORM, 128, 4, 4, GL_UNSIGNED_NORMALIZED, NULL, NULL, NeverSupported);
+
+ // B5G6R5 in D3D11 is treated the same as R5G6B5 in D3D9, so reuse the R5G6B5 functions used by the D3D9 renderer.
+ // The same applies to B4G4R4A4 and B5G5R5A1 with A4R4G4B4 and A1R5G5B5 respectively.
+ AddDXGIFormat(&map, DXGI_FORMAT_B5G6R5_UNORM, 16, 1, 1, GL_UNSIGNED_NORMALIZED, GenerateMip<R5G6B5>, ReadColor<R5G6B5, GLfloat>, RequiresFeatureLevel<D3D_FEATURE_LEVEL_9_1>);
+ AddDXGIFormat(&map, DXGI_FORMAT_B4G4R4A4_UNORM, 16, 1, 1, GL_UNSIGNED_NORMALIZED, GenerateMip<A4R4G4B4>, ReadColor<A4R4G4B4, GLfloat>, NeverSupported);
+ AddDXGIFormat(&map, DXGI_FORMAT_B5G5R5A1_UNORM, 16, 1, 1, GL_UNSIGNED_NORMALIZED, GenerateMip<A1R5G5B5>, ReadColor<A1R5G5B5, GLfloat>, NeverSupported);
// Useful formats for vertex buffers
- AddDXGIFormat(&map, DXGI_FORMAT_R16_UNORM, 16, 1, 1, GL_UNSIGNED_NORMALIZED, NULL, NULL);
- AddDXGIFormat(&map, DXGI_FORMAT_R16_SNORM, 16, 1, 1, GL_SIGNED_NORMALIZED, NULL, NULL);
- AddDXGIFormat(&map, DXGI_FORMAT_R16G16_UNORM, 32, 1, 1, GL_UNSIGNED_NORMALIZED, NULL, NULL);
- AddDXGIFormat(&map, DXGI_FORMAT_R16G16_SNORM, 32, 1, 1, GL_SIGNED_NORMALIZED, NULL, NULL);
- AddDXGIFormat(&map, DXGI_FORMAT_R16G16B16A16_UNORM, 64, 1, 1, GL_UNSIGNED_NORMALIZED, NULL, NULL);
- AddDXGIFormat(&map, DXGI_FORMAT_R16G16B16A16_SNORM, 64, 1, 1, GL_SIGNED_NORMALIZED, NULL, NULL);
+ AddDXGIFormat(&map, DXGI_FORMAT_R16_UNORM, 16, 1, 1, GL_UNSIGNED_NORMALIZED, NULL, NULL, NeverSupported);
+ AddDXGIFormat(&map, DXGI_FORMAT_R16_SNORM, 16, 1, 1, GL_SIGNED_NORMALIZED, NULL, NULL, NeverSupported);
+ AddDXGIFormat(&map, DXGI_FORMAT_R16G16_UNORM, 32, 1, 1, GL_UNSIGNED_NORMALIZED, NULL, NULL, NeverSupported);
+ AddDXGIFormat(&map, DXGI_FORMAT_R16G16_SNORM, 32, 1, 1, GL_SIGNED_NORMALIZED, NULL, NULL, NeverSupported);
+ AddDXGIFormat(&map, DXGI_FORMAT_R16G16B16A16_UNORM, 64, 1, 1, GL_UNSIGNED_NORMALIZED, NULL, NULL, NeverSupported);
+ AddDXGIFormat(&map, DXGI_FORMAT_R16G16B16A16_SNORM, 64, 1, 1, GL_SIGNED_NORMALIZED, NULL, NULL, NeverSupported);
return map;
}
@@ -436,613 +466,8 @@ const DXGIFormat &GetDXGIFormatInfo(DXGI_FORMAT format)
}
}
-struct SwizzleSizeType
-{
- size_t maxComponentSize;
- GLenum componentType;
-
- SwizzleSizeType()
- : maxComponentSize(0), componentType(GL_NONE)
- { }
-
- SwizzleSizeType(size_t maxComponentSize, GLenum componentType)
- : maxComponentSize(maxComponentSize), componentType(componentType)
- { }
-
- bool operator<(const SwizzleSizeType& other) const
- {
- return (maxComponentSize != other.maxComponentSize) ? (maxComponentSize < other.maxComponentSize)
- : (componentType < other.componentType);
- }
-};
-
-struct SwizzleFormatInfo
-{
- DXGI_FORMAT mTexFormat;
- DXGI_FORMAT mSRVFormat;
- DXGI_FORMAT mRTVFormat;
-
- SwizzleFormatInfo()
- : mTexFormat(DXGI_FORMAT_UNKNOWN), mSRVFormat(DXGI_FORMAT_UNKNOWN), mRTVFormat(DXGI_FORMAT_UNKNOWN)
- { }
-
- SwizzleFormatInfo(DXGI_FORMAT texFormat, DXGI_FORMAT srvFormat, DXGI_FORMAT rtvFormat)
- : mTexFormat(texFormat), mSRVFormat(srvFormat), mRTVFormat(rtvFormat)
- { }
-};
-
-typedef std::map<SwizzleSizeType, SwizzleFormatInfo> SwizzleInfoMap;
-typedef std::pair<SwizzleSizeType, SwizzleFormatInfo> SwizzleInfoPair;
-
-static SwizzleInfoMap BuildSwizzleInfoMap()
-{
- SwizzleInfoMap map;
-
- map.insert(SwizzleInfoPair(SwizzleSizeType( 8, GL_UNSIGNED_NORMALIZED), SwizzleFormatInfo(DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM )));
- map.insert(SwizzleInfoPair(SwizzleSizeType(16, GL_UNSIGNED_NORMALIZED), SwizzleFormatInfo(DXGI_FORMAT_R16G16B16A16_UNORM, DXGI_FORMAT_R16G16B16A16_UNORM, DXGI_FORMAT_R16G16B16A16_UNORM)));
- map.insert(SwizzleInfoPair(SwizzleSizeType(24, GL_UNSIGNED_NORMALIZED), SwizzleFormatInfo(DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT)));
- map.insert(SwizzleInfoPair(SwizzleSizeType(32, GL_UNSIGNED_NORMALIZED), SwizzleFormatInfo(DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT)));
-
- map.insert(SwizzleInfoPair(SwizzleSizeType( 8, GL_SIGNED_NORMALIZED ), SwizzleFormatInfo(DXGI_FORMAT_R8G8B8A8_SNORM, DXGI_FORMAT_R8G8B8A8_SNORM, DXGI_FORMAT_R8G8B8A8_SNORM )));
-
- map.insert(SwizzleInfoPair(SwizzleSizeType(16, GL_FLOAT ), SwizzleFormatInfo(DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT)));
- map.insert(SwizzleInfoPair(SwizzleSizeType(32, GL_FLOAT ), SwizzleFormatInfo(DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT)));
-
- map.insert(SwizzleInfoPair(SwizzleSizeType( 8, GL_UNSIGNED_INT ), SwizzleFormatInfo(DXGI_FORMAT_R8G8B8A8_UINT, DXGI_FORMAT_R8G8B8A8_UINT, DXGI_FORMAT_R8G8B8A8_UINT )));
- map.insert(SwizzleInfoPair(SwizzleSizeType(16, GL_UNSIGNED_INT ), SwizzleFormatInfo(DXGI_FORMAT_R16G16B16A16_UINT, DXGI_FORMAT_R16G16B16A16_UINT, DXGI_FORMAT_R16G16B16A16_UINT )));
- map.insert(SwizzleInfoPair(SwizzleSizeType(32, GL_UNSIGNED_INT ), SwizzleFormatInfo(DXGI_FORMAT_R32G32B32A32_UINT, DXGI_FORMAT_R32G32B32A32_UINT, DXGI_FORMAT_R32G32B32A32_UINT )));
-
- map.insert(SwizzleInfoPair(SwizzleSizeType( 8, GL_INT ), SwizzleFormatInfo(DXGI_FORMAT_R8G8B8A8_SINT, DXGI_FORMAT_R8G8B8A8_SINT, DXGI_FORMAT_R8G8B8A8_SINT )));
- map.insert(SwizzleInfoPair(SwizzleSizeType(16, GL_INT ), SwizzleFormatInfo(DXGI_FORMAT_R16G16B16A16_SINT, DXGI_FORMAT_R16G16B16A16_SINT, DXGI_FORMAT_R16G16B16A16_SINT )));
- map.insert(SwizzleInfoPair(SwizzleSizeType(32, GL_INT ), SwizzleFormatInfo(DXGI_FORMAT_R32G32B32A32_SINT, DXGI_FORMAT_R32G32B32A32_SINT, DXGI_FORMAT_R32G32B32A32_SINT )));
-
- return map;
-}
-
-typedef std::pair<GLint, InitializeTextureDataFunction> InternalFormatInitializerPair;
-typedef std::map<GLint, InitializeTextureDataFunction> InternalFormatInitializerMap;
-
-static InternalFormatInitializerMap BuildInternalFormatInitializerMap()
-{
- InternalFormatInitializerMap map;
-
- map.insert(InternalFormatInitializerPair(GL_RGB8, Initialize4ComponentData<GLubyte, 0x00, 0x00, 0x00, 0xFF> ));
- map.insert(InternalFormatInitializerPair(GL_RGB565, Initialize4ComponentData<GLubyte, 0x00, 0x00, 0x00, 0xFF> ));
- map.insert(InternalFormatInitializerPair(GL_SRGB8, Initialize4ComponentData<GLubyte, 0x00, 0x00, 0x00, 0xFF> ));
- map.insert(InternalFormatInitializerPair(GL_RGB16F, Initialize4ComponentData<GLhalf, 0x0000, 0x0000, 0x0000, gl::Float16One>));
- map.insert(InternalFormatInitializerPair(GL_RGB32F, Initialize4ComponentData<GLfloat, 0x00000000, 0x00000000, 0x00000000, gl::Float32One>));
- map.insert(InternalFormatInitializerPair(GL_RGB8UI, Initialize4ComponentData<GLubyte, 0x00, 0x00, 0x00, 0x01> ));
- map.insert(InternalFormatInitializerPair(GL_RGB8I, Initialize4ComponentData<GLbyte, 0x00, 0x00, 0x00, 0x01> ));
- map.insert(InternalFormatInitializerPair(GL_RGB16UI, Initialize4ComponentData<GLushort, 0x0000, 0x0000, 0x0000, 0x0001> ));
- map.insert(InternalFormatInitializerPair(GL_RGB16I, Initialize4ComponentData<GLshort, 0x0000, 0x0000, 0x0000, 0x0001> ));
- map.insert(InternalFormatInitializerPair(GL_RGB32UI, Initialize4ComponentData<GLuint, 0x00000000, 0x00000000, 0x00000000, 0x00000001> ));
- map.insert(InternalFormatInitializerPair(GL_RGB32I, Initialize4ComponentData<GLint, 0x00000000, 0x00000000, 0x00000000, 0x00000001> ));
-
- return map;
-}
-
-// ES3 image loading functions vary based on the internal format and data type given,
-// this map type determines the loading function from the internal format and type supplied
-// to glTex*Image*D and the destination DXGI_FORMAT. Source formats and types are taken from
-// Tables 3.2 and 3.3 of the ES 3 spec.
-typedef std::pair<GLenum, LoadImageFunction> TypeLoadFunctionPair;
-typedef std::map<GLenum, std::vector<TypeLoadFunctionPair> > D3D11LoadFunctionMap;
-
-static void UnimplementedLoadFunction(size_t width, size_t height, size_t depth,
- const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch,
- uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch)
-{
- UNIMPLEMENTED();
-}
-
-static void UnreachableLoadFunction(size_t width, size_t height, size_t depth,
- const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch,
- uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch)
-{
- UNREACHABLE();
-}
-
-// A helper function to insert data into the D3D11LoadFunctionMap with fewer characters.
-static inline void InsertLoadFunction(D3D11LoadFunctionMap *map, GLenum internalFormat, GLenum type,
- LoadImageFunction loadFunc)
-{
- (*map)[internalFormat].push_back(TypeLoadFunctionPair(type, loadFunc));
-}
-
-D3D11LoadFunctionMap BuildD3D11_FL9_3_LoadFunctionMap()
-{
- D3D11LoadFunctionMap map;
-
- // From GL_EXT_texture_storage. Also used by GL_ALPHA8
- // On feature level 9_3, A8_UNORM doesn't support mipmaps, so we must use RGBA8 instead
- InsertLoadFunction(&map, GL_ALPHA8_EXT, GL_UNSIGNED_BYTE, LoadA8ToRGBA8);
-
- return map;
-}
-
-D3D11LoadFunctionMap BuildD3D11_FL10_0Plus_LoadFunctionMap()
-{
- D3D11LoadFunctionMap map;
-
- // From GL_EXT_texture_storage. Also used by GL_ALPHA8
- InsertLoadFunction(&map, GL_ALPHA8_EXT, GL_UNSIGNED_BYTE, LoadToNative<GLubyte, 1>);
-
- return map;
-}
-
-D3D11LoadFunctionMap BuildBaseD3D11LoadFunctionMap()
-{
- D3D11LoadFunctionMap map;
-
- // | Internal format | Type | Load function |
- InsertLoadFunction(&map, GL_RGBA8, GL_UNSIGNED_BYTE, LoadToNative<GLubyte, 4> );
- InsertLoadFunction(&map, GL_RGB5_A1, GL_UNSIGNED_BYTE, LoadToNative<GLubyte, 4> );
- InsertLoadFunction(&map, GL_RGBA4, GL_UNSIGNED_BYTE, LoadToNative<GLubyte, 4> );
- InsertLoadFunction(&map, GL_SRGB8_ALPHA8, GL_UNSIGNED_BYTE, LoadToNative<GLubyte, 4> );
- InsertLoadFunction(&map, GL_RGBA8_SNORM, GL_BYTE, LoadToNative<GLbyte, 4> );
- InsertLoadFunction(&map, GL_RGBA4, GL_UNSIGNED_SHORT_4_4_4_4, LoadRGBA4ToRGBA8 );
- InsertLoadFunction(&map, GL_RGB10_A2, GL_UNSIGNED_INT_2_10_10_10_REV, LoadToNative<GLuint, 1> );
- InsertLoadFunction(&map, GL_RGB5_A1, GL_UNSIGNED_SHORT_5_5_5_1, LoadRGB5A1ToRGBA8 );
- InsertLoadFunction(&map, GL_RGB5_A1, GL_UNSIGNED_INT_2_10_10_10_REV, LoadRGB10A2ToRGBA8 );
- InsertLoadFunction(&map, GL_RGBA16F, GL_HALF_FLOAT, LoadToNative<GLhalf, 4> );
- InsertLoadFunction(&map, GL_RGBA16F, GL_HALF_FLOAT_OES, LoadToNative<GLhalf, 4> );
- InsertLoadFunction(&map, GL_RGBA32F, GL_FLOAT, LoadToNative<GLfloat, 4> );
- InsertLoadFunction(&map, GL_RGBA16F, GL_FLOAT, Load32FTo16F<4> );
- InsertLoadFunction(&map, GL_RGBA8UI, GL_UNSIGNED_BYTE, LoadToNative<GLubyte, 4> );
- InsertLoadFunction(&map, GL_RGBA8I, GL_BYTE, LoadToNative<GLbyte, 4> );
- InsertLoadFunction(&map, GL_RGBA16UI, GL_UNSIGNED_SHORT, LoadToNative<GLushort, 4> );
- InsertLoadFunction(&map, GL_RGBA16I, GL_SHORT, LoadToNative<GLshort, 4> );
- InsertLoadFunction(&map, GL_RGBA32UI, GL_UNSIGNED_INT, LoadToNative<GLuint, 4> );
- InsertLoadFunction(&map, GL_RGBA32I, GL_INT, LoadToNative<GLint, 4> );
- InsertLoadFunction(&map, GL_RGB10_A2UI, GL_UNSIGNED_INT_2_10_10_10_REV, LoadToNative<GLuint, 1> );
- InsertLoadFunction(&map, GL_RGB8, GL_UNSIGNED_BYTE, LoadToNative3To4<GLubyte, 0xFF> );
- InsertLoadFunction(&map, GL_RGB565, GL_UNSIGNED_BYTE, LoadToNative3To4<GLubyte, 0xFF> );
- InsertLoadFunction(&map, GL_SRGB8, GL_UNSIGNED_BYTE, LoadToNative3To4<GLubyte, 0xFF> );
- InsertLoadFunction(&map, GL_RGB8_SNORM, GL_BYTE, LoadToNative3To4<GLbyte, 0x7F> );
- InsertLoadFunction(&map, GL_RGB565, GL_UNSIGNED_SHORT_5_6_5, LoadR5G6B5ToRGBA8 );
- InsertLoadFunction(&map, GL_R11F_G11F_B10F, GL_UNSIGNED_INT_10F_11F_11F_REV, LoadToNative<GLuint, 1> );
- InsertLoadFunction(&map, GL_RGB9_E5, GL_UNSIGNED_INT_5_9_9_9_REV, LoadToNative<GLuint, 1> );
- InsertLoadFunction(&map, GL_RGB16F, GL_HALF_FLOAT, LoadToNative3To4<GLhalf, gl::Float16One>);
- InsertLoadFunction(&map, GL_RGB16F, GL_HALF_FLOAT_OES, LoadToNative3To4<GLhalf, gl::Float16One>);
- InsertLoadFunction(&map, GL_R11F_G11F_B10F, GL_HALF_FLOAT, LoadRGB16FToRG11B10F );
- InsertLoadFunction(&map, GL_R11F_G11F_B10F, GL_HALF_FLOAT_OES, LoadRGB16FToRG11B10F );
- InsertLoadFunction(&map, GL_RGB9_E5, GL_HALF_FLOAT, LoadRGB16FToRGB9E5 );
- InsertLoadFunction(&map, GL_RGB9_E5, GL_HALF_FLOAT_OES, LoadRGB16FToRGB9E5 );
- InsertLoadFunction(&map, GL_RGB32F, GL_FLOAT, LoadToNative3To4<GLfloat, gl::Float32One>);
- InsertLoadFunction(&map, GL_RGB16F, GL_FLOAT, LoadRGB32FToRGBA16F );
- InsertLoadFunction(&map, GL_R11F_G11F_B10F, GL_FLOAT, LoadRGB32FToRG11B10F );
- InsertLoadFunction(&map, GL_RGB9_E5, GL_FLOAT, LoadRGB32FToRGB9E5 );
- InsertLoadFunction(&map, GL_RGB8UI, GL_UNSIGNED_BYTE, LoadToNative3To4<GLubyte, 0x01> );
- InsertLoadFunction(&map, GL_RGB8I, GL_BYTE, LoadToNative3To4<GLbyte, 0x01> );
- InsertLoadFunction(&map, GL_RGB16UI, GL_UNSIGNED_SHORT, LoadToNative3To4<GLushort, 0x0001> );
- InsertLoadFunction(&map, GL_RGB16I, GL_SHORT, LoadToNative3To4<GLshort, 0x0001> );
- InsertLoadFunction(&map, GL_RGB32UI, GL_UNSIGNED_INT, LoadToNative3To4<GLuint, 0x00000001> );
- InsertLoadFunction(&map, GL_RGB32I, GL_INT, LoadToNative3To4<GLint, 0x00000001> );
- InsertLoadFunction(&map, GL_RG8, GL_UNSIGNED_BYTE, LoadToNative<GLubyte, 2> );
- InsertLoadFunction(&map, GL_RG8_SNORM, GL_BYTE, LoadToNative<GLbyte, 2> );
- InsertLoadFunction(&map, GL_RG16F, GL_HALF_FLOAT, LoadToNative<GLhalf, 2> );
- InsertLoadFunction(&map, GL_RG16F, GL_HALF_FLOAT_OES, LoadToNative<GLhalf, 2> );
- InsertLoadFunction(&map, GL_RG32F, GL_FLOAT, LoadToNative<GLfloat, 2> );
- InsertLoadFunction(&map, GL_RG16F, GL_FLOAT, Load32FTo16F<2> );
- InsertLoadFunction(&map, GL_RG8UI, GL_UNSIGNED_BYTE, LoadToNative<GLubyte, 2> );
- InsertLoadFunction(&map, GL_RG8I, GL_BYTE, LoadToNative<GLbyte, 2> );
- InsertLoadFunction(&map, GL_RG16UI, GL_UNSIGNED_SHORT, LoadToNative<GLushort, 2> );
- InsertLoadFunction(&map, GL_RG16I, GL_SHORT, LoadToNative<GLshort, 2> );
- InsertLoadFunction(&map, GL_RG32UI, GL_UNSIGNED_INT, LoadToNative<GLuint, 2> );
- InsertLoadFunction(&map, GL_RG32I, GL_INT, LoadToNative<GLint, 2> );
- InsertLoadFunction(&map, GL_R8, GL_UNSIGNED_BYTE, LoadToNative<GLubyte, 1> );
- InsertLoadFunction(&map, GL_R8_SNORM, GL_BYTE, LoadToNative<GLbyte, 1> );
- InsertLoadFunction(&map, GL_R16F, GL_HALF_FLOAT, LoadToNative<GLhalf, 1> );
- InsertLoadFunction(&map, GL_R16F, GL_HALF_FLOAT_OES, LoadToNative<GLhalf, 1> );
- InsertLoadFunction(&map, GL_R32F, GL_FLOAT, LoadToNative<GLfloat, 1> );
- InsertLoadFunction(&map, GL_R16F, GL_FLOAT, Load32FTo16F<1> );
- InsertLoadFunction(&map, GL_R8UI, GL_UNSIGNED_BYTE, LoadToNative<GLubyte, 1> );
- InsertLoadFunction(&map, GL_R8I, GL_BYTE, LoadToNative<GLbyte, 1> );
- InsertLoadFunction(&map, GL_R16UI, GL_UNSIGNED_SHORT, LoadToNative<GLushort, 1> );
- InsertLoadFunction(&map, GL_R16I, GL_SHORT, LoadToNative<GLshort, 1> );
- InsertLoadFunction(&map, GL_R32UI, GL_UNSIGNED_INT, LoadToNative<GLuint, 1> );
- InsertLoadFunction(&map, GL_R32I, GL_INT, LoadToNative<GLint, 1> );
- InsertLoadFunction(&map, GL_DEPTH_COMPONENT16, GL_UNSIGNED_SHORT, LoadToNative<GLushort, 1> );
- InsertLoadFunction(&map, GL_DEPTH_COMPONENT24, GL_UNSIGNED_INT, LoadR32ToR24G8 );
- InsertLoadFunction(&map, GL_DEPTH_COMPONENT16, GL_UNSIGNED_INT, LoadR32ToR16 );
- InsertLoadFunction(&map, GL_DEPTH_COMPONENT32F, GL_FLOAT, LoadToNative<GLfloat, 1> );
- InsertLoadFunction(&map, GL_DEPTH24_STENCIL8, GL_UNSIGNED_INT_24_8, LoadR32ToR24G8 );
- InsertLoadFunction(&map, GL_DEPTH32F_STENCIL8, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, LoadToNative<GLuint, 2> );
-
- // Unsized formats
- // Load functions are unreachable because they are converted to sized internal formats based on
- // the format and type before loading takes place.
- InsertLoadFunction(&map, GL_RGBA, GL_UNSIGNED_BYTE, UnreachableLoadFunction );
- InsertLoadFunction(&map, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, UnreachableLoadFunction );
- InsertLoadFunction(&map, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, UnreachableLoadFunction );
- InsertLoadFunction(&map, GL_RGB, GL_UNSIGNED_BYTE, UnreachableLoadFunction );
- InsertLoadFunction(&map, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, UnreachableLoadFunction );
- InsertLoadFunction(&map, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, UnreachableLoadFunction );
- InsertLoadFunction(&map, GL_LUMINANCE, GL_UNSIGNED_BYTE, UnreachableLoadFunction );
- InsertLoadFunction(&map, GL_ALPHA, GL_UNSIGNED_BYTE, UnreachableLoadFunction );
-
- // From GL_OES_texture_float
- InsertLoadFunction(&map, GL_LUMINANCE_ALPHA, GL_FLOAT, LoadLA32FToRGBA32F );
- InsertLoadFunction(&map, GL_LUMINANCE, GL_FLOAT, LoadL32FToRGBA32F );
- InsertLoadFunction(&map, GL_ALPHA, GL_FLOAT, LoadA32FToRGBA32F );
-
- // From GL_OES_texture_half_float
- InsertLoadFunction(&map, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT, LoadLA16FToRGBA16F );
- InsertLoadFunction(&map, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT_OES, LoadLA16FToRGBA16F );
- InsertLoadFunction(&map, GL_LUMINANCE, GL_HALF_FLOAT, LoadL16FToRGBA16F );
- InsertLoadFunction(&map, GL_LUMINANCE, GL_HALF_FLOAT_OES, LoadL16FToRGBA16F );
- InsertLoadFunction(&map, GL_ALPHA, GL_HALF_FLOAT, LoadA16FToRGBA16F );
- InsertLoadFunction(&map, GL_ALPHA, GL_HALF_FLOAT_OES, LoadA16FToRGBA16F );
-
- // From GL_EXT_texture_storage
- // GL_ALPHA8_EXT GL_UNSIGNED_BYTE is in the feature-level-specific load function maps, due to differences between 9_3 and 10_0+
- InsertLoadFunction(&map, GL_LUMINANCE8_EXT, GL_UNSIGNED_BYTE, LoadL8ToRGBA8 );
- InsertLoadFunction(&map, GL_LUMINANCE8_ALPHA8_EXT, GL_UNSIGNED_BYTE, LoadLA8ToRGBA8 );
- InsertLoadFunction(&map, GL_ALPHA32F_EXT, GL_FLOAT, LoadA32FToRGBA32F );
- InsertLoadFunction(&map, GL_LUMINANCE32F_EXT, GL_FLOAT, LoadL32FToRGBA32F );
- InsertLoadFunction(&map, GL_LUMINANCE_ALPHA32F_EXT, GL_FLOAT, LoadLA32FToRGBA32F );
- InsertLoadFunction(&map, GL_ALPHA16F_EXT, GL_HALF_FLOAT, LoadA16FToRGBA16F );
- InsertLoadFunction(&map, GL_ALPHA16F_EXT, GL_HALF_FLOAT_OES, LoadA16FToRGBA16F );
- InsertLoadFunction(&map, GL_LUMINANCE16F_EXT, GL_HALF_FLOAT, LoadL16FToRGBA16F );
- InsertLoadFunction(&map, GL_LUMINANCE16F_EXT, GL_HALF_FLOAT_OES, LoadL16FToRGBA16F );
- InsertLoadFunction(&map, GL_LUMINANCE_ALPHA16F_EXT, GL_HALF_FLOAT, LoadLA16FToRGBA16F );
- InsertLoadFunction(&map, GL_LUMINANCE_ALPHA16F_EXT, GL_HALF_FLOAT_OES, LoadLA16FToRGBA16F );
-
- // From GL_ANGLE_depth_texture
- InsertLoadFunction(&map, GL_DEPTH_COMPONENT32_OES, GL_UNSIGNED_INT, LoadR32ToR24G8 );
-
- // From GL_EXT_texture_format_BGRA8888
- InsertLoadFunction(&map, GL_BGRA8_EXT, GL_UNSIGNED_BYTE, LoadToNative<GLubyte, 4> );
- InsertLoadFunction(&map, GL_BGRA4_ANGLEX, GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT, LoadRGBA4ToRGBA8 );
- InsertLoadFunction(&map, GL_BGRA4_ANGLEX, GL_UNSIGNED_BYTE, LoadToNative<GLubyte, 4> );
- InsertLoadFunction(&map, GL_BGR5_A1_ANGLEX, GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT, LoadRGB5A1ToRGBA8 );
- InsertLoadFunction(&map, GL_BGR5_A1_ANGLEX, GL_UNSIGNED_BYTE, LoadToNative<GLubyte, 4> );
-
- // Compressed formats
- // From ES 3.0.1 spec, table 3.16
- // | Internal format | Type | Load function |
- InsertLoadFunction(&map, GL_COMPRESSED_R11_EAC, GL_UNSIGNED_BYTE, UnimplementedLoadFunction );
- InsertLoadFunction(&map, GL_COMPRESSED_R11_EAC, GL_UNSIGNED_BYTE, UnimplementedLoadFunction );
- InsertLoadFunction(&map, GL_COMPRESSED_SIGNED_R11_EAC, GL_UNSIGNED_BYTE, UnimplementedLoadFunction );
- InsertLoadFunction(&map, GL_COMPRESSED_RG11_EAC, GL_UNSIGNED_BYTE, UnimplementedLoadFunction );
- InsertLoadFunction(&map, GL_COMPRESSED_SIGNED_RG11_EAC, GL_UNSIGNED_BYTE, UnimplementedLoadFunction );
- InsertLoadFunction(&map, GL_COMPRESSED_RGB8_ETC2, GL_UNSIGNED_BYTE, UnimplementedLoadFunction );
- InsertLoadFunction(&map, GL_COMPRESSED_SRGB8_ETC2, GL_UNSIGNED_BYTE, UnimplementedLoadFunction );
- InsertLoadFunction(&map, GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL_UNSIGNED_BYTE, UnimplementedLoadFunction );
- InsertLoadFunction(&map, GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL_UNSIGNED_BYTE, UnimplementedLoadFunction );
- InsertLoadFunction(&map, GL_COMPRESSED_RGBA8_ETC2_EAC, GL_UNSIGNED_BYTE, UnimplementedLoadFunction );
- InsertLoadFunction(&map, GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC, GL_UNSIGNED_BYTE, UnimplementedLoadFunction );
-
- // From GL_EXT_texture_compression_dxt1
- InsertLoadFunction(&map, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_UNSIGNED_BYTE, LoadCompressedToNative<4, 4, 8>);
- InsertLoadFunction(&map, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, GL_UNSIGNED_BYTE, LoadCompressedToNative<4, 4, 8>);
-
- // From GL_ANGLE_texture_compression_dxt3
- InsertLoadFunction(&map, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, GL_UNSIGNED_BYTE, LoadCompressedToNative<4, 4, 16>);
-
- // From GL_ANGLE_texture_compression_dxt5
- InsertLoadFunction(&map, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, GL_UNSIGNED_BYTE, LoadCompressedToNative<4, 4, 16>);
-
- return map;
-}
-
-// For sized GL internal formats, there is only one corresponding D3D11 format. This map type allows
-// querying for the DXGI texture formats to use for textures, SRVs, RTVs and DSVs given a GL internal
-// format.
-typedef std::map<GLenum, TextureFormat> D3D11ES3FormatMap;
-
-TextureFormat::TextureFormat()
- : texFormat(DXGI_FORMAT_UNKNOWN),
- srvFormat(DXGI_FORMAT_UNKNOWN),
- rtvFormat(DXGI_FORMAT_UNKNOWN),
- dsvFormat(DXGI_FORMAT_UNKNOWN),
- renderFormat(DXGI_FORMAT_UNKNOWN),
- swizzleTexFormat(DXGI_FORMAT_UNKNOWN),
- swizzleSRVFormat(DXGI_FORMAT_UNKNOWN),
- swizzleRTVFormat(DXGI_FORMAT_UNKNOWN),
- dataInitializerFunction(NULL),
- loadFunctions()
-{
-}
-
-static inline void InsertD3D11FormatInfoBase(D3D11ES3FormatMap *formatMap, const D3D11LoadFunctionMap &flLoadFunctions, GLenum internalFormat, DXGI_FORMAT texFormat,
- DXGI_FORMAT srvFormat, DXGI_FORMAT rtvFormat, DXGI_FORMAT dsvFormat)
-{
- TextureFormat info;
- info.texFormat = texFormat;
- info.srvFormat = srvFormat;
- info.rtvFormat = rtvFormat;
- info.dsvFormat = dsvFormat;
-
- // Given a GL internal format, the renderFormat is the DSV format if it is depth- or stencil-renderable,
- // the RTV format if it is color-renderable, and the (nonrenderable) texture format otherwise.
- if (dsvFormat != DXGI_FORMAT_UNKNOWN)
- {
- info.renderFormat = dsvFormat;
- }
- else if (rtvFormat != DXGI_FORMAT_UNKNOWN)
- {
- info.renderFormat = rtvFormat;
- }
- else if (texFormat != DXGI_FORMAT_UNKNOWN)
- {
- info.renderFormat = texFormat;
- }
- else
- {
- info.renderFormat = DXGI_FORMAT_UNKNOWN;
- }
-
- // Compute the swizzle formats
- const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat);
- if (internalFormat != GL_NONE && formatInfo.pixelBytes > 0)
- {
- if (formatInfo.componentCount != 4 || texFormat == DXGI_FORMAT_UNKNOWN ||
- srvFormat == DXGI_FORMAT_UNKNOWN || rtvFormat == DXGI_FORMAT_UNKNOWN)
- {
- // Get the maximum sized component
- unsigned int maxBits = 1;
- if (formatInfo.compressed)
- {
- unsigned int compressedBitsPerBlock = formatInfo.pixelBytes * 8;
- unsigned int blockSize = formatInfo.compressedBlockWidth * formatInfo.compressedBlockHeight;
- maxBits = std::max(compressedBitsPerBlock / blockSize, maxBits);
- }
- else
- {
- maxBits = std::max(maxBits, formatInfo.alphaBits);
- maxBits = std::max(maxBits, formatInfo.redBits);
- maxBits = std::max(maxBits, formatInfo.greenBits);
- maxBits = std::max(maxBits, formatInfo.blueBits);
- maxBits = std::max(maxBits, formatInfo.luminanceBits);
- maxBits = std::max(maxBits, formatInfo.depthBits);
- }
-
- maxBits = roundUp(maxBits, 8U);
-
- static const SwizzleInfoMap swizzleMap = BuildSwizzleInfoMap();
- SwizzleInfoMap::const_iterator swizzleIter = swizzleMap.find(SwizzleSizeType(maxBits, formatInfo.componentType));
- ASSERT(swizzleIter != swizzleMap.end());
-
- const SwizzleFormatInfo &swizzleInfo = swizzleIter->second;
- info.swizzleTexFormat = swizzleInfo.mTexFormat;
- info.swizzleSRVFormat = swizzleInfo.mSRVFormat;
- info.swizzleRTVFormat = swizzleInfo.mRTVFormat;
- }
- else
- {
- // The original texture format is suitable for swizzle operations
- info.swizzleTexFormat = texFormat;
- info.swizzleSRVFormat = srvFormat;
- info.swizzleRTVFormat = rtvFormat;
- }
- }
- else
- {
- // Not possible to swizzle with this texture format since it is either unsized or GL_NONE
- info.swizzleTexFormat = DXGI_FORMAT_UNKNOWN;
- info.swizzleSRVFormat = DXGI_FORMAT_UNKNOWN;
- info.swizzleRTVFormat = DXGI_FORMAT_UNKNOWN;
- }
-
- // Check if there is an initialization function for this texture format
- static const InternalFormatInitializerMap initializerMap = BuildInternalFormatInitializerMap();
- InternalFormatInitializerMap::const_iterator initializerIter = initializerMap.find(internalFormat);
- info.dataInitializerFunction = (initializerIter != initializerMap.end()) ? initializerIter->second : NULL;
-
- // Gather all the load functions for this internal format from the base list
- static const D3D11LoadFunctionMap loadFunctions = BuildBaseD3D11LoadFunctionMap();
- D3D11LoadFunctionMap::const_iterator loadFunctionIter = loadFunctions.find(internalFormat);
- if (loadFunctionIter != loadFunctions.end())
- {
- const std::vector<TypeLoadFunctionPair> &loadFunctionVector = loadFunctionIter->second;
- for (size_t i = 0; i < loadFunctionVector.size(); i++)
- {
- GLenum type = loadFunctionVector[i].first;
- LoadImageFunction function = loadFunctionVector[i].second;
- info.loadFunctions.insert(std::make_pair(type, function));
- }
- }
-
- // Gather load functions for this internal format from the feature-level-specific list
- D3D11LoadFunctionMap::const_iterator flLoadFunctionIter = flLoadFunctions.find(internalFormat);
- if (flLoadFunctionIter != flLoadFunctions.end())
- {
- const std::vector<TypeLoadFunctionPair> &flLoadFunctionVector = flLoadFunctionIter->second;
- for (size_t i = 0; i < flLoadFunctionVector.size(); i++)
- {
- GLenum type = flLoadFunctionVector[i].first;
- LoadImageFunction function = flLoadFunctionVector[i].second;
- info.loadFunctions.insert(std::make_pair(type, function));
- }
- }
-
- formatMap->insert(std::make_pair(internalFormat, info));
-}
-
-static inline void InsertD3D11_FL9_3_FormatInfo(D3D11ES3FormatMap *map, GLenum internalFormat, DXGI_FORMAT texFormat,
- DXGI_FORMAT srvFormat, DXGI_FORMAT rtvFormat, DXGI_FORMAT dsvFormat)
-{
- static const D3D11LoadFunctionMap flLoadFunctions = BuildD3D11_FL9_3_LoadFunctionMap();
- InsertD3D11FormatInfoBase(map, flLoadFunctions, internalFormat, texFormat, srvFormat, rtvFormat, dsvFormat);
-}
-
-static inline void InsertD3D11FormatInfo(D3D11ES3FormatMap *map, GLenum internalFormat, DXGI_FORMAT texFormat,
- DXGI_FORMAT srvFormat, DXGI_FORMAT rtvFormat, DXGI_FORMAT dsvFormat)
-{
- static const D3D11LoadFunctionMap flLoadFunctions = BuildD3D11_FL10_0Plus_LoadFunctionMap();
- InsertD3D11FormatInfoBase(map, flLoadFunctions, internalFormat, texFormat, srvFormat, rtvFormat, dsvFormat);
-}
-
-static D3D11ES3FormatMap BuildD3D11_FL9_3FormatOverrideMap()
-{
- // D3D11 Feature Level 9_3 doesn't support as many texture formats as Feature Level 10_0+.
- // In particular, it doesn't support:
- // - mipmaps on DXGI_FORMAT_A8_NORM
- // - *_TYPELESS formats
- // - DXGI_FORMAT_D32_FLOAT_S8X24_UINT or DXGI_FORMAT_D32_FLOAT
-
- D3D11ES3FormatMap map;
-
- // | GL internal format | D3D11 texture format | D3D11 SRV format | D3D11 RTV format | D3D11 DSV format
- InsertD3D11_FL9_3_FormatInfo(&map, GL_ALPHA, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN);
- InsertD3D11_FL9_3_FormatInfo(&map, GL_ALPHA8_EXT, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN);
- InsertD3D11_FL9_3_FormatInfo(&map, GL_DEPTH_COMPONENT16, DXGI_FORMAT_D16_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_D16_UNORM);
- InsertD3D11_FL9_3_FormatInfo(&map, GL_DEPTH_COMPONENT24, DXGI_FORMAT_D24_UNORM_S8_UINT, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_D24_UNORM_S8_UINT);
- InsertD3D11_FL9_3_FormatInfo(&map, GL_DEPTH_COMPONENT32F, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN);
- InsertD3D11_FL9_3_FormatInfo(&map, GL_DEPTH24_STENCIL8, DXGI_FORMAT_D24_UNORM_S8_UINT, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_D24_UNORM_S8_UINT);
- InsertD3D11_FL9_3_FormatInfo(&map, GL_DEPTH32F_STENCIL8, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN);
- InsertD3D11_FL9_3_FormatInfo(&map, GL_STENCIL_INDEX8, DXGI_FORMAT_D24_UNORM_S8_UINT, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_D24_UNORM_S8_UINT);
-
- return map;
-}
-
-static D3D11ES3FormatMap BuildD3D11FormatMap()
-{
- D3D11ES3FormatMap map;
-
- // | GL internal format | D3D11 texture format | D3D11 SRV format | D3D11 RTV format | D3D11 DSV format |
- InsertD3D11FormatInfo(&map, GL_NONE, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN);
- InsertD3D11FormatInfo(&map, GL_R8, DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_UNKNOWN);
- InsertD3D11FormatInfo(&map, GL_R8_SNORM, DXGI_FORMAT_R8_SNORM, DXGI_FORMAT_R8_SNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN);
- InsertD3D11FormatInfo(&map, GL_RG8, DXGI_FORMAT_R8G8_UNORM, DXGI_FORMAT_R8G8_UNORM, DXGI_FORMAT_R8G8_UNORM, DXGI_FORMAT_UNKNOWN);
- InsertD3D11FormatInfo(&map, GL_RG8_SNORM, DXGI_FORMAT_R8G8_SNORM, DXGI_FORMAT_R8G8_SNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN);
- InsertD3D11FormatInfo(&map, GL_RGB8, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN);
- InsertD3D11FormatInfo(&map, GL_RGB8_SNORM, DXGI_FORMAT_R8G8B8A8_SNORM, DXGI_FORMAT_R8G8B8A8_SNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN);
- InsertD3D11FormatInfo(&map, GL_RGB565, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN);
- InsertD3D11FormatInfo(&map, GL_RGBA4, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN);
- InsertD3D11FormatInfo(&map, GL_RGB5_A1, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN);
- InsertD3D11FormatInfo(&map, GL_RGBA8, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN);
- InsertD3D11FormatInfo(&map, GL_RGBA8_SNORM, DXGI_FORMAT_R8G8B8A8_SNORM, DXGI_FORMAT_R8G8B8A8_SNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN);
- InsertD3D11FormatInfo(&map, GL_RGB10_A2, DXGI_FORMAT_R10G10B10A2_UNORM, DXGI_FORMAT_R10G10B10A2_UNORM, DXGI_FORMAT_R10G10B10A2_UNORM, DXGI_FORMAT_UNKNOWN);
- InsertD3D11FormatInfo(&map, GL_RGB10_A2UI, DXGI_FORMAT_R10G10B10A2_UINT, DXGI_FORMAT_R10G10B10A2_UINT, DXGI_FORMAT_R10G10B10A2_UINT, DXGI_FORMAT_UNKNOWN);
- InsertD3D11FormatInfo(&map, GL_SRGB8, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN);
- InsertD3D11FormatInfo(&map, GL_SRGB8_ALPHA8, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, DXGI_FORMAT_UNKNOWN);
- InsertD3D11FormatInfo(&map, GL_R16F, DXGI_FORMAT_R16_FLOAT, DXGI_FORMAT_R16_FLOAT, DXGI_FORMAT_R16_FLOAT, DXGI_FORMAT_UNKNOWN);
- InsertD3D11FormatInfo(&map, GL_RG16F, DXGI_FORMAT_R16G16_FLOAT, DXGI_FORMAT_R16G16_FLOAT, DXGI_FORMAT_R16G16_FLOAT, DXGI_FORMAT_UNKNOWN);
- InsertD3D11FormatInfo(&map, GL_RGB16F, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_UNKNOWN);
- InsertD3D11FormatInfo(&map, GL_RGBA16F, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_UNKNOWN);
- InsertD3D11FormatInfo(&map, GL_R32F, DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_UNKNOWN);
- InsertD3D11FormatInfo(&map, GL_RG32F, DXGI_FORMAT_R32G32_FLOAT, DXGI_FORMAT_R32G32_FLOAT, DXGI_FORMAT_R32G32_FLOAT, DXGI_FORMAT_UNKNOWN);
- InsertD3D11FormatInfo(&map, GL_RGB32F, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_UNKNOWN);
- InsertD3D11FormatInfo(&map, GL_RGBA32F, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_UNKNOWN);
- InsertD3D11FormatInfo(&map, GL_R11F_G11F_B10F, DXGI_FORMAT_R11G11B10_FLOAT, DXGI_FORMAT_R11G11B10_FLOAT, DXGI_FORMAT_R11G11B10_FLOAT, DXGI_FORMAT_UNKNOWN);
- InsertD3D11FormatInfo(&map, GL_RGB9_E5, DXGI_FORMAT_R9G9B9E5_SHAREDEXP, DXGI_FORMAT_R9G9B9E5_SHAREDEXP, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN);
- InsertD3D11FormatInfo(&map, GL_R8I, DXGI_FORMAT_R8_SINT, DXGI_FORMAT_R8_SINT, DXGI_FORMAT_R8_SINT, DXGI_FORMAT_UNKNOWN);
- InsertD3D11FormatInfo(&map, GL_R8UI, DXGI_FORMAT_R8_UINT, DXGI_FORMAT_R8_UINT, DXGI_FORMAT_R8_UINT, DXGI_FORMAT_UNKNOWN);
- InsertD3D11FormatInfo(&map, GL_R16I, DXGI_FORMAT_R16_SINT, DXGI_FORMAT_R16_SINT, DXGI_FORMAT_R16_SINT, DXGI_FORMAT_UNKNOWN);
- InsertD3D11FormatInfo(&map, GL_R16UI, DXGI_FORMAT_R16_UINT, DXGI_FORMAT_R16_UINT, DXGI_FORMAT_R16_UINT, DXGI_FORMAT_UNKNOWN);
- InsertD3D11FormatInfo(&map, GL_R32I, DXGI_FORMAT_R32_SINT, DXGI_FORMAT_R32_SINT, DXGI_FORMAT_R32_SINT, DXGI_FORMAT_UNKNOWN);
- InsertD3D11FormatInfo(&map, GL_R32UI, DXGI_FORMAT_R32_UINT, DXGI_FORMAT_R32_UINT, DXGI_FORMAT_R32_UINT, DXGI_FORMAT_UNKNOWN);
- InsertD3D11FormatInfo(&map, GL_RG8I, DXGI_FORMAT_R8G8_SINT, DXGI_FORMAT_R8G8_SINT, DXGI_FORMAT_R8G8_SINT, DXGI_FORMAT_UNKNOWN);
- InsertD3D11FormatInfo(&map, GL_RG8UI, DXGI_FORMAT_R8G8_UINT, DXGI_FORMAT_R8G8_UINT, DXGI_FORMAT_R8G8_UINT, DXGI_FORMAT_UNKNOWN);
- InsertD3D11FormatInfo(&map, GL_RG16I, DXGI_FORMAT_R16G16_SINT, DXGI_FORMAT_R16G16_SINT, DXGI_FORMAT_R16G16_SINT, DXGI_FORMAT_UNKNOWN);
- InsertD3D11FormatInfo(&map, GL_RG16UI, DXGI_FORMAT_R16G16_UINT, DXGI_FORMAT_R16G16_UINT, DXGI_FORMAT_R16G16_UINT, DXGI_FORMAT_UNKNOWN);
- InsertD3D11FormatInfo(&map, GL_RG32I, DXGI_FORMAT_R32G32_SINT, DXGI_FORMAT_R32G32_SINT, DXGI_FORMAT_R32G32_SINT, DXGI_FORMAT_UNKNOWN);
- InsertD3D11FormatInfo(&map, GL_RG32UI, DXGI_FORMAT_R32G32_UINT, DXGI_FORMAT_R32G32_UINT, DXGI_FORMAT_R32G32_UINT, DXGI_FORMAT_UNKNOWN);
- InsertD3D11FormatInfo(&map, GL_RGB8I, DXGI_FORMAT_R8G8B8A8_SINT, DXGI_FORMAT_R8G8B8A8_SINT, DXGI_FORMAT_R8G8B8A8_SINT, DXGI_FORMAT_UNKNOWN);
- InsertD3D11FormatInfo(&map, GL_RGB8UI, DXGI_FORMAT_R8G8B8A8_UINT, DXGI_FORMAT_R8G8B8A8_UINT, DXGI_FORMAT_R8G8B8A8_UINT, DXGI_FORMAT_UNKNOWN);
- InsertD3D11FormatInfo(&map, GL_RGB16I, DXGI_FORMAT_R16G16B16A16_SINT, DXGI_FORMAT_R16G16B16A16_SINT, DXGI_FORMAT_R16G16B16A16_SINT, DXGI_FORMAT_UNKNOWN);
- InsertD3D11FormatInfo(&map, GL_RGB16UI, DXGI_FORMAT_R16G16B16A16_UINT, DXGI_FORMAT_R16G16B16A16_UINT, DXGI_FORMAT_R16G16B16A16_UINT, DXGI_FORMAT_UNKNOWN);
- InsertD3D11FormatInfo(&map, GL_RGB32I, DXGI_FORMAT_R32G32B32A32_SINT, DXGI_FORMAT_R32G32B32A32_SINT, DXGI_FORMAT_R32G32B32A32_SINT, DXGI_FORMAT_UNKNOWN);
- InsertD3D11FormatInfo(&map, GL_RGB32UI, DXGI_FORMAT_R32G32B32A32_UINT, DXGI_FORMAT_R32G32B32A32_UINT, DXGI_FORMAT_R32G32B32A32_UINT, DXGI_FORMAT_UNKNOWN);
- InsertD3D11FormatInfo(&map, GL_RGBA8I, DXGI_FORMAT_R8G8B8A8_SINT, DXGI_FORMAT_R8G8B8A8_SINT, DXGI_FORMAT_R8G8B8A8_SINT, DXGI_FORMAT_UNKNOWN);
- InsertD3D11FormatInfo(&map, GL_RGBA8UI, DXGI_FORMAT_R8G8B8A8_UINT, DXGI_FORMAT_R8G8B8A8_UINT, DXGI_FORMAT_R8G8B8A8_UINT, DXGI_FORMAT_UNKNOWN);
- InsertD3D11FormatInfo(&map, GL_RGBA16I, DXGI_FORMAT_R16G16B16A16_SINT, DXGI_FORMAT_R16G16B16A16_SINT, DXGI_FORMAT_R16G16B16A16_SINT, DXGI_FORMAT_UNKNOWN);
- InsertD3D11FormatInfo(&map, GL_RGBA16UI, DXGI_FORMAT_R16G16B16A16_UINT, DXGI_FORMAT_R16G16B16A16_UINT, DXGI_FORMAT_R16G16B16A16_UINT, DXGI_FORMAT_UNKNOWN);
- InsertD3D11FormatInfo(&map, GL_RGBA32I, DXGI_FORMAT_R32G32B32A32_SINT, DXGI_FORMAT_R32G32B32A32_SINT, DXGI_FORMAT_R32G32B32A32_SINT, DXGI_FORMAT_UNKNOWN);
- InsertD3D11FormatInfo(&map, GL_RGBA32UI, DXGI_FORMAT_R32G32B32A32_UINT, DXGI_FORMAT_R32G32B32A32_UINT, DXGI_FORMAT_R32G32B32A32_UINT, DXGI_FORMAT_UNKNOWN);
-
- // Unsized formats, TODO: Are types of float and half float allowed for the unsized types? Would it change the DXGI format?
- InsertD3D11FormatInfo(&map, GL_ALPHA, DXGI_FORMAT_A8_UNORM, DXGI_FORMAT_A8_UNORM, DXGI_FORMAT_A8_UNORM, DXGI_FORMAT_UNKNOWN);
- InsertD3D11FormatInfo(&map, GL_LUMINANCE, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN);
- InsertD3D11FormatInfo(&map, GL_LUMINANCE_ALPHA, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN);
- InsertD3D11FormatInfo(&map, GL_RGB, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN);
- InsertD3D11FormatInfo(&map, GL_RGBA, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN);
- InsertD3D11FormatInfo(&map, GL_BGRA_EXT, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_UNKNOWN);
-
- // From GL_EXT_texture_storage
- // | GL internal format | D3D11 texture format | D3D11 SRV format | D3D11 RTV format | D3D11 DSV format |
- InsertD3D11FormatInfo(&map, GL_ALPHA8_EXT, DXGI_FORMAT_A8_UNORM, DXGI_FORMAT_A8_UNORM, DXGI_FORMAT_A8_UNORM, DXGI_FORMAT_UNKNOWN );
- InsertD3D11FormatInfo(&map, GL_LUMINANCE8_EXT, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN );
- InsertD3D11FormatInfo(&map, GL_ALPHA32F_EXT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_UNKNOWN );
- InsertD3D11FormatInfo(&map, GL_LUMINANCE32F_EXT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_UNKNOWN );
- InsertD3D11FormatInfo(&map, GL_ALPHA16F_EXT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_UNKNOWN );
- InsertD3D11FormatInfo(&map, GL_LUMINANCE16F_EXT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_UNKNOWN );
- InsertD3D11FormatInfo(&map, GL_LUMINANCE8_ALPHA8_EXT, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN );
- InsertD3D11FormatInfo(&map, GL_LUMINANCE_ALPHA32F_EXT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_UNKNOWN );
- InsertD3D11FormatInfo(&map, GL_LUMINANCE_ALPHA16F_EXT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_UNKNOWN );
- InsertD3D11FormatInfo(&map, GL_BGRA8_EXT, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_UNKNOWN );
- InsertD3D11FormatInfo(&map, GL_BGRA4_ANGLEX, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_UNKNOWN );
- InsertD3D11FormatInfo(&map, GL_BGR5_A1_ANGLEX, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_UNKNOWN );
-
- // Depth stencil formats
- InsertD3D11FormatInfo(&map, GL_DEPTH_COMPONENT16, DXGI_FORMAT_R16_TYPELESS, DXGI_FORMAT_R16_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_D16_UNORM );
- InsertD3D11FormatInfo(&map, GL_DEPTH_COMPONENT24, DXGI_FORMAT_R24G8_TYPELESS, DXGI_FORMAT_R24_UNORM_X8_TYPELESS, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_D24_UNORM_S8_UINT );
- InsertD3D11FormatInfo(&map, GL_DEPTH_COMPONENT32F, DXGI_FORMAT_R32_TYPELESS, DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_D32_FLOAT );
- InsertD3D11FormatInfo(&map, GL_DEPTH24_STENCIL8, DXGI_FORMAT_R24G8_TYPELESS, DXGI_FORMAT_R24_UNORM_X8_TYPELESS, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_D24_UNORM_S8_UINT );
- InsertD3D11FormatInfo(&map, GL_DEPTH32F_STENCIL8, DXGI_FORMAT_R32G8X24_TYPELESS, DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_D32_FLOAT_S8X24_UINT);
- InsertD3D11FormatInfo(&map, GL_STENCIL_INDEX8, DXGI_FORMAT_R24G8_TYPELESS, DXGI_FORMAT_X24_TYPELESS_G8_UINT, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_D24_UNORM_S8_UINT );
-
- // From GL_ANGLE_depth_texture
- // Since D3D11 doesn't have a D32_UNORM format, use D24S8 which has comparable precision and matches the ES3 format.
- InsertD3D11FormatInfo(&map, GL_DEPTH_COMPONENT32_OES, DXGI_FORMAT_R24G8_TYPELESS, DXGI_FORMAT_R24_UNORM_X8_TYPELESS, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_D24_UNORM_S8_UINT);
-
- // Compressed formats, From ES 3.0.1 spec, table 3.16
- // | GL internal format | D3D11 texture format | D3D11 SRV format | D3D11 RTV format | D3D11 DSV format |
- InsertD3D11FormatInfo(&map, GL_COMPRESSED_R11_EAC, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN);
- InsertD3D11FormatInfo(&map, GL_COMPRESSED_SIGNED_R11_EAC, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN);
- InsertD3D11FormatInfo(&map, GL_COMPRESSED_RG11_EAC, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN);
- InsertD3D11FormatInfo(&map, GL_COMPRESSED_SIGNED_RG11_EAC, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN);
- InsertD3D11FormatInfo(&map, GL_COMPRESSED_RGB8_ETC2, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN);
- InsertD3D11FormatInfo(&map, GL_COMPRESSED_SRGB8_ETC2, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN);
- InsertD3D11FormatInfo(&map, GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN);
- InsertD3D11FormatInfo(&map, GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN);
- InsertD3D11FormatInfo(&map, GL_COMPRESSED_RGBA8_ETC2_EAC, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN);
- InsertD3D11FormatInfo(&map, GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN);
-
- // From GL_EXT_texture_compression_dxt1
- InsertD3D11FormatInfo(&map, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, DXGI_FORMAT_BC1_UNORM, DXGI_FORMAT_BC1_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN);
- InsertD3D11FormatInfo(&map, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, DXGI_FORMAT_BC1_UNORM, DXGI_FORMAT_BC1_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN);
-
- // From GL_ANGLE_texture_compression_dxt3
- InsertD3D11FormatInfo(&map, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, DXGI_FORMAT_BC2_UNORM, DXGI_FORMAT_BC2_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN);
-
- // From GL_ANGLE_texture_compression_dxt5
- InsertD3D11FormatInfo(&map, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, DXGI_FORMAT_BC3_UNORM, DXGI_FORMAT_BC3_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN);
-
- return map;
-}
-
-const TextureFormat &GetTextureFormatInfo(GLenum internalFormat, D3D_FEATURE_LEVEL featureLevel)
-{
- static const D3D11ES3FormatMap formatMap = BuildD3D11FormatMap();
- static const D3D11ES3FormatMap formatMapFL9_3Override = BuildD3D11_FL9_3FormatOverrideMap();
-
- if (featureLevel == D3D_FEATURE_LEVEL_9_3)
- {
- // First see if the internalFormat has a special map for FL9_3
- D3D11ES3FormatMap::const_iterator fl9_3Iter = formatMapFL9_3Override.find(internalFormat);
- if (fl9_3Iter != formatMapFL9_3Override.end())
- {
- return fl9_3Iter->second;
- }
- }
-
- D3D11ES3FormatMap::const_iterator iter = formatMap.find(internalFormat);
- if (iter != formatMap.end())
- {
- return iter->second;
- }
- else
- {
- static const TextureFormat defaultInfo;
- return defaultInfo;
- }
-}
-
-typedef std::map<gl::VertexFormat, VertexFormat> D3D11VertexFormatInfoMap;
-typedef std::pair<gl::VertexFormat, VertexFormat> D3D11VertexFormatPair;
+typedef std::map<gl::VertexFormatType, VertexFormat> D3D11VertexFormatInfoMap;
+typedef std::pair<gl::VertexFormatType, VertexFormat> D3D11VertexFormatPair;
VertexFormat::VertexFormat()
: conversionType(VERTEX_CONVERT_NONE),
@@ -1051,30 +476,31 @@ VertexFormat::VertexFormat()
{
}
-static void AddVertexFormatInfo(D3D11VertexFormatInfoMap *map, GLenum inputType, GLboolean normalized, GLuint componentCount,
- VertexConversionType conversionType, DXGI_FORMAT nativeFormat, VertexCopyFunction copyFunction)
+VertexFormat::VertexFormat(VertexConversionType conversionTypeIn,
+ DXGI_FORMAT nativeFormatIn,
+ VertexCopyFunction copyFunctionIn)
+ : conversionType(conversionTypeIn),
+ nativeFormat(nativeFormatIn),
+ copyFunction(copyFunctionIn)
{
- gl::VertexFormat inputFormat(inputType, normalized, componentCount, false);
-
- VertexFormat info;
- info.conversionType = conversionType;
- info.nativeFormat = nativeFormat;
- info.copyFunction = copyFunction;
-
- map->insert(D3D11VertexFormatPair(inputFormat, info));
}
-static void AddIntegerVertexFormatInfo(D3D11VertexFormatInfoMap *map, GLenum inputType, GLuint componentCount,
- VertexConversionType conversionType, DXGI_FORMAT nativeFormat, VertexCopyFunction copyFunction)
+static void AddVertexFormatInfo(D3D11VertexFormatInfoMap *map,
+ GLenum inputType,
+ GLboolean normalized,
+ GLuint componentCount,
+ VertexConversionType conversionType,
+ DXGI_FORMAT nativeFormat,
+ VertexCopyFunction copyFunction)
{
- gl::VertexFormat inputFormat(inputType, GL_FALSE, componentCount, true);
+ gl::VertexFormatType formatType = gl::GetVertexFormatType(inputType, normalized, componentCount, false);
VertexFormat info;
info.conversionType = conversionType;
info.nativeFormat = nativeFormat;
info.copyFunction = copyFunction;
- map->insert(D3D11VertexFormatPair(inputFormat, info));
+ map->insert(D3D11VertexFormatPair(formatType, info));
}
static D3D11VertexFormatInfoMap BuildD3D11_FL9_3VertexFormatInfoOverrideMap()
@@ -1139,187 +565,536 @@ static D3D11VertexFormatInfoMap BuildD3D11_FL9_3VertexFormatInfoOverrideMap()
return map;
}
-static D3D11VertexFormatInfoMap BuildD3D11VertexFormatInfoMap()
+const VertexFormat &GetVertexFormatInfo(gl::VertexFormatType vertexFormatType, D3D_FEATURE_LEVEL featureLevel)
{
- D3D11VertexFormatInfoMap map;
+ if (featureLevel == D3D_FEATURE_LEVEL_9_3)
+ {
+ static const D3D11VertexFormatInfoMap vertexFormatMapFL9_3Override =
+ BuildD3D11_FL9_3VertexFormatInfoOverrideMap();
- // TODO: column legend
+ // First see if the format has a special mapping for FL9_3
+ auto iter = vertexFormatMapFL9_3Override.find(vertexFormatType);
+ if (iter != vertexFormatMapFL9_3Override.end())
+ {
+ return iter->second;
+ }
+ }
- //
- // Float formats
- //
+ switch (vertexFormatType)
+ {
+ //
+ // Float formats
+ //
- // GL_BYTE -- un-normalized
- AddVertexFormatInfo(&map, GL_BYTE, GL_FALSE, 1, VERTEX_CONVERT_GPU, DXGI_FORMAT_R8_SINT, &CopyNativeVertexData<GLbyte, 1, 1, 0>);
- AddVertexFormatInfo(&map, GL_BYTE, GL_FALSE, 2, VERTEX_CONVERT_GPU, DXGI_FORMAT_R8G8_SINT, &CopyNativeVertexData<GLbyte, 2, 2, 0>);
- AddVertexFormatInfo(&map, GL_BYTE, GL_FALSE, 3, VERTEX_CONVERT_BOTH, DXGI_FORMAT_R8G8B8A8_SINT, &CopyNativeVertexData<GLbyte, 3, 4, 1>);
- AddVertexFormatInfo(&map, GL_BYTE, GL_FALSE, 4, VERTEX_CONVERT_GPU, DXGI_FORMAT_R8G8B8A8_SINT, &CopyNativeVertexData<GLbyte, 4, 4, 0>);
+ // GL_BYTE -- un-normalized
+ case gl::VERTEX_FORMAT_SBYTE1:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R8_SINT, &CopyNativeVertexData<GLbyte, 1, 1, 0>);
+ return info;
+ }
+ case gl::VERTEX_FORMAT_SBYTE2:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R8G8_SINT, &CopyNativeVertexData<GLbyte, 2, 2, 0>);
+ return info;
+ }
+ case gl::VERTEX_FORMAT_SBYTE3:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_BOTH, DXGI_FORMAT_R8G8B8A8_SINT, &CopyNativeVertexData<GLbyte, 3, 4, 1>);
+ return info;
+ }
+ case gl::VERTEX_FORMAT_SBYTE4:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R8G8B8A8_SINT, &CopyNativeVertexData<GLbyte, 4, 4, 0>);
+ return info;
+ }
- // GL_BYTE -- normalized
- AddVertexFormatInfo(&map, GL_BYTE, GL_TRUE, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8_SNORM, &CopyNativeVertexData<GLbyte, 1, 1, 0>);
- AddVertexFormatInfo(&map, GL_BYTE, GL_TRUE, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8_SNORM, &CopyNativeVertexData<GLbyte, 2, 2, 0>);
- AddVertexFormatInfo(&map, GL_BYTE, GL_TRUE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R8G8B8A8_SNORM, &CopyNativeVertexData<GLbyte, 3, 4, INT8_MAX>);
- AddVertexFormatInfo(&map, GL_BYTE, GL_TRUE, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8B8A8_SNORM, &CopyNativeVertexData<GLbyte, 4, 4, 0>);
+ // GL_BYTE -- normalized
+ case gl::VERTEX_FORMAT_SBYTE1_NORM:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R8_SNORM, &CopyNativeVertexData<GLbyte, 1, 1, 0>);
+ return info;
+ }
+ case gl::VERTEX_FORMAT_SBYTE2_NORM:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8_SNORM, &CopyNativeVertexData<GLbyte, 2, 2, 0>);
+ return info;
+ }
+ case gl::VERTEX_FORMAT_SBYTE3_NORM:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R8G8B8A8_SNORM, &CopyNativeVertexData<GLbyte, 3, 4, INT8_MAX>);
+ return info;
+ }
+ case gl::VERTEX_FORMAT_SBYTE4_NORM:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8B8A8_SNORM, &CopyNativeVertexData<GLbyte, 4, 4, 0>);
+ return info;
+ }
- // GL_UNSIGNED_BYTE -- un-normalized
- AddVertexFormatInfo(&map, GL_UNSIGNED_BYTE, GL_FALSE, 1, VERTEX_CONVERT_GPU, DXGI_FORMAT_R8_UINT, &CopyNativeVertexData<GLubyte, 1, 1, 0>);
- AddVertexFormatInfo(&map, GL_UNSIGNED_BYTE, GL_FALSE, 2, VERTEX_CONVERT_GPU, DXGI_FORMAT_R8G8_UINT, &CopyNativeVertexData<GLubyte, 2, 2, 0>);
- AddVertexFormatInfo(&map, GL_UNSIGNED_BYTE, GL_FALSE, 3, VERTEX_CONVERT_BOTH, DXGI_FORMAT_R8G8B8A8_UINT, &CopyNativeVertexData<GLubyte, 3, 4, 1>);
- AddVertexFormatInfo(&map, GL_UNSIGNED_BYTE, GL_FALSE, 4, VERTEX_CONVERT_GPU, DXGI_FORMAT_R8G8B8A8_UINT, &CopyNativeVertexData<GLubyte, 4, 4, 0>);
+ // GL_UNSIGNED_BYTE -- un-normalized
+ case gl::VERTEX_FORMAT_UBYTE1:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R8_UINT, &CopyNativeVertexData<GLubyte, 1, 1, 0>);
+ return info;
+ }
+ case gl::VERTEX_FORMAT_UBYTE2:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R8G8_UINT, &CopyNativeVertexData<GLubyte, 2, 2, 0>);
+ return info;
+ }
+ case gl::VERTEX_FORMAT_UBYTE3:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_BOTH, DXGI_FORMAT_R8G8B8A8_UINT, &CopyNativeVertexData<GLubyte, 3, 4, 1>);
+ return info;
+ }
+ case gl::VERTEX_FORMAT_UBYTE4:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R8G8B8A8_UINT, &CopyNativeVertexData<GLubyte, 4, 4, 0>);
+ return info;
+ }
- // GL_UNSIGNED_BYTE -- normalized
- AddVertexFormatInfo(&map, GL_UNSIGNED_BYTE, GL_TRUE, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8_UNORM, &CopyNativeVertexData<GLubyte, 1, 1, 0>);
- AddVertexFormatInfo(&map, GL_UNSIGNED_BYTE, GL_TRUE, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8_UNORM, &CopyNativeVertexData<GLubyte, 2, 2, 0>);
- AddVertexFormatInfo(&map, GL_UNSIGNED_BYTE, GL_TRUE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R8G8B8A8_UNORM, &CopyNativeVertexData<GLubyte, 3, 4, UINT8_MAX>);
- AddVertexFormatInfo(&map, GL_UNSIGNED_BYTE, GL_TRUE, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8B8A8_UNORM, &CopyNativeVertexData<GLubyte, 4, 4, 0>);
+ // GL_UNSIGNED_BYTE -- normalized
+ case gl::VERTEX_FORMAT_UBYTE1_NORM:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R8_UNORM, &CopyNativeVertexData<GLubyte, 1, 1, 0>);
+ return info;
+ }
+ case gl::VERTEX_FORMAT_UBYTE2_NORM:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8_UNORM, &CopyNativeVertexData<GLubyte, 2, 2, 0>);
+ return info;
+ }
+ case gl::VERTEX_FORMAT_UBYTE3_NORM:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R8G8B8A8_UNORM, &CopyNativeVertexData<GLubyte, 3, 4, UINT8_MAX>);
+ return info;
+ }
+ case gl::VERTEX_FORMAT_UBYTE4_NORM:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8B8A8_UNORM, &CopyNativeVertexData<GLubyte, 4, 4, 0>);
+ return info;
+ }
- // GL_SHORT -- un-normalized
- AddVertexFormatInfo(&map, GL_SHORT, GL_FALSE, 1, VERTEX_CONVERT_GPU, DXGI_FORMAT_R16_SINT, &CopyNativeVertexData<GLshort, 1, 1, 0>);
- AddVertexFormatInfo(&map, GL_SHORT, GL_FALSE, 2, VERTEX_CONVERT_GPU, DXGI_FORMAT_R16G16_SINT, &CopyNativeVertexData<GLshort, 2, 2, 0>);
- AddVertexFormatInfo(&map, GL_SHORT, GL_FALSE, 3, VERTEX_CONVERT_BOTH, DXGI_FORMAT_R16G16B16A16_SINT, &CopyNativeVertexData<GLshort, 3, 4, 1>);
- AddVertexFormatInfo(&map, GL_SHORT, GL_FALSE, 4, VERTEX_CONVERT_GPU, DXGI_FORMAT_R16G16B16A16_SINT, &CopyNativeVertexData<GLshort, 4, 4, 0>);
+ // GL_SHORT -- un-normalized
+ case gl::VERTEX_FORMAT_SSHORT1:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R16_SINT, &CopyNativeVertexData<GLshort, 1, 1, 0>);
+ return info;
+ }
+ case gl::VERTEX_FORMAT_SSHORT2:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R16G16_SINT, &CopyNativeVertexData<GLshort, 2, 2, 0>);
+ return info;
+ }
+ case gl::VERTEX_FORMAT_SSHORT3:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_BOTH, DXGI_FORMAT_R16G16B16A16_SINT, &CopyNativeVertexData<GLshort, 3, 4, 1>);
+ return info;
+ }
+ case gl::VERTEX_FORMAT_SSHORT4:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R16G16B16A16_SINT, &CopyNativeVertexData<GLshort, 4, 4, 0>);
+ return info;
+ }
- // GL_SHORT -- normalized
- AddVertexFormatInfo(&map, GL_SHORT, GL_TRUE, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16_SNORM, &CopyNativeVertexData<GLshort, 1, 1, 0>);
- AddVertexFormatInfo(&map, GL_SHORT, GL_TRUE, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16_SNORM, &CopyNativeVertexData<GLshort, 2, 2, 0>);
- AddVertexFormatInfo(&map, GL_SHORT, GL_TRUE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16B16A16_SNORM, &CopyNativeVertexData<GLshort, 3, 4, INT16_MAX>);
- AddVertexFormatInfo(&map, GL_SHORT, GL_TRUE, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16B16A16_SNORM, &CopyNativeVertexData<GLshort, 4, 4, 0>);
+ // GL_SHORT -- normalized
+ case gl::VERTEX_FORMAT_SSHORT1_NORM:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R16_SNORM, &CopyNativeVertexData<GLshort, 1, 1, 0>);
+ return info;
+ }
+ case gl::VERTEX_FORMAT_SSHORT2_NORM:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16_SNORM, &CopyNativeVertexData<GLshort, 2, 2, 0>);
+ return info;
+ }
+ case gl::VERTEX_FORMAT_SSHORT3_NORM:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16B16A16_SNORM, &CopyNativeVertexData<GLshort, 3, 4, INT16_MAX>);
+ return info;
+ }
+ case gl::VERTEX_FORMAT_SSHORT4_NORM:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16B16A16_SNORM, &CopyNativeVertexData<GLshort, 4, 4, 0>);
+ return info;
+ }
- // GL_UNSIGNED_SHORT -- un-normalized
- AddVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_FALSE, 1, VERTEX_CONVERT_GPU, DXGI_FORMAT_R16_UINT, &CopyNativeVertexData<GLushort, 1, 1, 0>);
- AddVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_FALSE, 2, VERTEX_CONVERT_GPU, DXGI_FORMAT_R16G16_UINT, &CopyNativeVertexData<GLushort, 2, 2, 0>);
- AddVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_FALSE, 3, VERTEX_CONVERT_BOTH, DXGI_FORMAT_R16G16B16A16_UINT, &CopyNativeVertexData<GLushort, 3, 4, 1>);
- AddVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_FALSE, 4, VERTEX_CONVERT_GPU, DXGI_FORMAT_R16G16B16A16_UINT, &CopyNativeVertexData<GLushort, 4, 4, 0>);
+ // GL_UNSIGNED_SHORT -- un-normalized
+ case gl::VERTEX_FORMAT_USHORT1:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R16_UINT, &CopyNativeVertexData<GLushort, 1, 1, 0>);
+ return info;
+ }
+ case gl::VERTEX_FORMAT_USHORT2:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R16G16_UINT, &CopyNativeVertexData<GLushort, 2, 2, 0>);
+ return info;
+ }
+ case gl::VERTEX_FORMAT_USHORT3:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_BOTH, DXGI_FORMAT_R16G16B16A16_UINT, &CopyNativeVertexData<GLushort, 3, 4, 1>);
+ return info;
+ }
+ case gl::VERTEX_FORMAT_USHORT4:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R16G16B16A16_UINT, &CopyNativeVertexData<GLushort, 4, 4, 0>);
+ return info;
+ }
- // GL_UNSIGNED_SHORT -- normalized
- AddVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_TRUE, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16_UNORM, &CopyNativeVertexData<GLushort, 1, 1, 0>);
- AddVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_TRUE, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16_UNORM, &CopyNativeVertexData<GLushort, 2, 2, 0>);
- AddVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_TRUE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16B16A16_UNORM, &CopyNativeVertexData<GLushort, 3, 4, UINT16_MAX>);
- AddVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_TRUE, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16B16A16_UNORM, &CopyNativeVertexData<GLushort, 4, 4, 0>);
-
- // GL_INT -- un-normalized
- AddVertexFormatInfo(&map, GL_INT, GL_FALSE, 1, VERTEX_CONVERT_GPU, DXGI_FORMAT_R32_SINT, &CopyNativeVertexData<GLint, 1, 1, 0>);
- AddVertexFormatInfo(&map, GL_INT, GL_FALSE, 2, VERTEX_CONVERT_GPU, DXGI_FORMAT_R32G32_SINT, &CopyNativeVertexData<GLint, 2, 2, 0>);
- AddVertexFormatInfo(&map, GL_INT, GL_FALSE, 3, VERTEX_CONVERT_GPU, DXGI_FORMAT_R32G32B32_SINT, &CopyNativeVertexData<GLint, 3, 3, 0>);
- AddVertexFormatInfo(&map, GL_INT, GL_FALSE, 4, VERTEX_CONVERT_GPU, DXGI_FORMAT_R32G32B32A32_SINT, &CopyNativeVertexData<GLint, 4, 4, 0>);
-
- // GL_INT -- normalized
- AddVertexFormatInfo(&map, GL_INT, GL_TRUE, 1, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32_FLOAT, &CopyTo32FVertexData<GLint, 1, 1, true>);
- AddVertexFormatInfo(&map, GL_INT, GL_TRUE, 2, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32_FLOAT, &CopyTo32FVertexData<GLint, 2, 2, true>);
- AddVertexFormatInfo(&map, GL_INT, GL_TRUE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32_FLOAT, &CopyTo32FVertexData<GLint, 3, 3, true>);
- AddVertexFormatInfo(&map, GL_INT, GL_TRUE, 4, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32A32_FLOAT, &CopyTo32FVertexData<GLint, 4, 4, true>);
-
- // GL_UNSIGNED_INT -- un-normalized
- AddVertexFormatInfo(&map, GL_UNSIGNED_INT, GL_FALSE, 1, VERTEX_CONVERT_GPU, DXGI_FORMAT_R32_UINT, &CopyNativeVertexData<GLuint, 1, 1, 0>);
- AddVertexFormatInfo(&map, GL_UNSIGNED_INT, GL_FALSE, 2, VERTEX_CONVERT_GPU, DXGI_FORMAT_R32G32_UINT, &CopyNativeVertexData<GLuint, 2, 2, 0>);
- AddVertexFormatInfo(&map, GL_UNSIGNED_INT, GL_FALSE, 3, VERTEX_CONVERT_GPU, DXGI_FORMAT_R32G32B32_UINT, &CopyNativeVertexData<GLuint, 3, 3, 0>);
- AddVertexFormatInfo(&map, GL_UNSIGNED_INT, GL_FALSE, 4, VERTEX_CONVERT_GPU, DXGI_FORMAT_R32G32B32A32_UINT, &CopyNativeVertexData<GLuint, 4, 4, 0>);
-
- // GL_UNSIGNED_INT -- normalized
- AddVertexFormatInfo(&map, GL_UNSIGNED_INT, GL_TRUE, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32_FLOAT, &CopyTo32FVertexData<GLuint, 1, 1, true>);
- AddVertexFormatInfo(&map, GL_UNSIGNED_INT, GL_TRUE, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32_FLOAT, &CopyTo32FVertexData<GLuint, 2, 2, true>);
- AddVertexFormatInfo(&map, GL_UNSIGNED_INT, GL_TRUE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32_FLOAT, &CopyTo32FVertexData<GLuint, 3, 3, true>);
- AddVertexFormatInfo(&map, GL_UNSIGNED_INT, GL_TRUE, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32B32A32_FLOAT, &CopyTo32FVertexData<GLuint, 4, 4, true>);
+ // GL_UNSIGNED_SHORT -- normalized
+ case gl::VERTEX_FORMAT_USHORT1_NORM:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R16_UNORM, &CopyNativeVertexData<GLushort, 1, 1, 0>);
+ return info;
+ }
+ case gl::VERTEX_FORMAT_USHORT2_NORM:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16_UNORM, &CopyNativeVertexData<GLushort, 2, 2, 0>);
+ return info;
+ }
+ case gl::VERTEX_FORMAT_USHORT3_NORM:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16B16A16_UNORM, &CopyNativeVertexData<GLushort, 3, 4, UINT16_MAX>);
+ return info;
+ }
+ case gl::VERTEX_FORMAT_USHORT4_NORM:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16B16A16_UNORM, &CopyNativeVertexData<GLushort, 4, 4, 0>);
+ return info;
+ }
- // GL_FIXED
- AddVertexFormatInfo(&map, GL_FIXED, GL_FALSE, 1, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32_FLOAT, &Copy32FixedTo32FVertexData<1, 1>);
- AddVertexFormatInfo(&map, GL_FIXED, GL_FALSE, 2, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32_FLOAT, &Copy32FixedTo32FVertexData<2, 2>);
- AddVertexFormatInfo(&map, GL_FIXED, GL_FALSE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32_FLOAT, &Copy32FixedTo32FVertexData<3, 3>);
- AddVertexFormatInfo(&map, GL_FIXED, GL_FALSE, 4, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32A32_FLOAT, &Copy32FixedTo32FVertexData<4, 4>);
+ // GL_INT -- un-normalized
+ case gl::VERTEX_FORMAT_SINT1:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R32_SINT, &CopyNativeVertexData<GLint, 1, 1, 0>);
+ return info;
+ }
+ case gl::VERTEX_FORMAT_SINT2:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R32G32_SINT, &CopyNativeVertexData<GLint, 2, 2, 0>);
+ return info;
+ }
+ case gl::VERTEX_FORMAT_SINT3:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R32G32B32_SINT, &CopyNativeVertexData<GLint, 3, 3, 0>);
+ return info;
+ }
+ case gl::VERTEX_FORMAT_SINT4:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R32G32B32A32_SINT, &CopyNativeVertexData<GLint, 4, 4, 0>);
+ return info;
+ }
- // GL_HALF_FLOAT
- AddVertexFormatInfo(&map, GL_HALF_FLOAT, GL_FALSE, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16_FLOAT, &CopyNativeVertexData<GLhalf, 1, 1, 0>);
- AddVertexFormatInfo(&map, GL_HALF_FLOAT, GL_FALSE, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16_FLOAT, &CopyNativeVertexData<GLhalf, 2, 2, 0>);
- AddVertexFormatInfo(&map, GL_HALF_FLOAT, GL_FALSE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16B16A16_FLOAT, &CopyNativeVertexData<GLhalf, 3, 4, gl::Float16One>);
- AddVertexFormatInfo(&map, GL_HALF_FLOAT, GL_FALSE, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16B16A16_FLOAT, &CopyNativeVertexData<GLhalf, 4, 4, 0>);
+ // GL_INT -- normalized
+ case gl::VERTEX_FORMAT_SINT1_NORM:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R32_FLOAT, &CopyTo32FVertexData<GLint, 1, 1, true>);
+ return info;
+ }
+ case gl::VERTEX_FORMAT_SINT2_NORM:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32_FLOAT, &CopyTo32FVertexData<GLint, 2, 2, true>);
+ return info;
+ }
+ case gl::VERTEX_FORMAT_SINT3_NORM:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32_FLOAT, &CopyTo32FVertexData<GLint, 3, 3, true>);
+ return info;
+ }
+ case gl::VERTEX_FORMAT_SINT4_NORM:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32A32_FLOAT, &CopyTo32FVertexData<GLint, 4, 4, true>);
+ return info;
+ }
- // GL_FLOAT
- AddVertexFormatInfo(&map, GL_FLOAT, GL_FALSE, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32_FLOAT, &CopyNativeVertexData<GLfloat, 1, 1, 0>);
- AddVertexFormatInfo(&map, GL_FLOAT, GL_FALSE, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32_FLOAT, &CopyNativeVertexData<GLfloat, 2, 2, 0>);
- AddVertexFormatInfo(&map, GL_FLOAT, GL_FALSE, 3, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32B32_FLOAT, &CopyNativeVertexData<GLfloat, 3, 3, 0>);
- AddVertexFormatInfo(&map, GL_FLOAT, GL_FALSE, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32B32A32_FLOAT, &CopyNativeVertexData<GLfloat, 4, 4, 0>);
-
- // GL_INT_2_10_10_10_REV
- AddVertexFormatInfo(&map, GL_INT_2_10_10_10_REV, GL_FALSE, 4, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32A32_FLOAT, &CopyXYZ10W2ToXYZW32FVertexData<true, false, true>);
- AddVertexFormatInfo(&map, GL_INT_2_10_10_10_REV, GL_TRUE, 4, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32A32_FLOAT, &CopyXYZ10W2ToXYZW32FVertexData<true, true, true>);
-
- // GL_UNSIGNED_INT_2_10_10_10_REV
- AddVertexFormatInfo(&map, GL_UNSIGNED_INT_2_10_10_10_REV, GL_FALSE, 4, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32A32_FLOAT, &CopyXYZ10W2ToXYZW32FVertexData<false, false, true>);
- AddVertexFormatInfo(&map, GL_UNSIGNED_INT_2_10_10_10_REV, GL_TRUE, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R10G10B10A2_UNORM, &CopyNativeVertexData<GLuint, 1, 1, 0>);
-
- //
- // Integer Formats
- //
-
- // GL_BYTE
- AddIntegerVertexFormatInfo(&map, GL_BYTE, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8_SINT, &CopyNativeVertexData<GLbyte, 1, 1, 0>);
- AddIntegerVertexFormatInfo(&map, GL_BYTE, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8_SINT, &CopyNativeVertexData<GLbyte, 2, 2, 0>);
- AddIntegerVertexFormatInfo(&map, GL_BYTE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R8G8B8A8_SINT, &CopyNativeVertexData<GLbyte, 3, 4, 1>);
- AddIntegerVertexFormatInfo(&map, GL_BYTE, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8B8A8_SINT, &CopyNativeVertexData<GLbyte, 4, 4, 0>);
-
- // GL_UNSIGNED_BYTE
- AddIntegerVertexFormatInfo(&map, GL_UNSIGNED_BYTE, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8_UINT, &CopyNativeVertexData<GLubyte, 1, 1, 0>);
- AddIntegerVertexFormatInfo(&map, GL_UNSIGNED_BYTE, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8_UINT, &CopyNativeVertexData<GLubyte, 2, 2, 0>);
- AddIntegerVertexFormatInfo(&map, GL_UNSIGNED_BYTE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R8G8B8A8_UINT, &CopyNativeVertexData<GLubyte, 3, 4, 1>);
- AddIntegerVertexFormatInfo(&map, GL_UNSIGNED_BYTE, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8B8A8_UINT, &CopyNativeVertexData<GLubyte, 4, 4, 0>);
-
- // GL_SHORT
- AddIntegerVertexFormatInfo(&map, GL_SHORT, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16_SINT, &CopyNativeVertexData<GLshort, 1, 1, 0>);
- AddIntegerVertexFormatInfo(&map, GL_SHORT, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16_SINT, &CopyNativeVertexData<GLshort, 2, 2, 0>);
- AddIntegerVertexFormatInfo(&map, GL_SHORT, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16B16A16_SINT, &CopyNativeVertexData<GLshort, 3, 4, 1>);
- AddIntegerVertexFormatInfo(&map, GL_SHORT, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16B16A16_SINT, &CopyNativeVertexData<GLshort, 4, 4, 0>);
-
- // GL_UNSIGNED_SHORT
- AddIntegerVertexFormatInfo(&map, GL_UNSIGNED_SHORT, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16_UINT, &CopyNativeVertexData<GLushort, 1, 1, 0>);
- AddIntegerVertexFormatInfo(&map, GL_UNSIGNED_SHORT, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16_UINT, &CopyNativeVertexData<GLushort, 2, 2, 0>);
- AddIntegerVertexFormatInfo(&map, GL_UNSIGNED_SHORT, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16B16A16_UINT, &CopyNativeVertexData<GLushort, 3, 4, 1>);
- AddIntegerVertexFormatInfo(&map, GL_UNSIGNED_SHORT, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16B16A16_UINT, &CopyNativeVertexData<GLushort, 4, 4, 0>);
-
- // GL_INT
- AddIntegerVertexFormatInfo(&map, GL_INT, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32_SINT, &CopyNativeVertexData<GLint, 1, 1, 0>);
- AddIntegerVertexFormatInfo(&map, GL_INT, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32_SINT, &CopyNativeVertexData<GLint, 2, 2, 0>);
- AddIntegerVertexFormatInfo(&map, GL_INT, 3, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32B32_SINT, &CopyNativeVertexData<GLint, 3, 3, 0>);
- AddIntegerVertexFormatInfo(&map, GL_INT, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32B32A32_SINT, &CopyNativeVertexData<GLint, 4, 4, 0>);
-
- // GL_UNSIGNED_INT
- AddIntegerVertexFormatInfo(&map, GL_UNSIGNED_INT, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32_SINT, &CopyNativeVertexData<GLuint, 1, 1, 0>);
- AddIntegerVertexFormatInfo(&map, GL_UNSIGNED_INT, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32_SINT, &CopyNativeVertexData<GLuint, 2, 2, 0>);
- AddIntegerVertexFormatInfo(&map, GL_UNSIGNED_INT, 3, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32B32_SINT, &CopyNativeVertexData<GLuint, 3, 3, 0>);
- AddIntegerVertexFormatInfo(&map, GL_UNSIGNED_INT, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32B32A32_SINT, &CopyNativeVertexData<GLuint, 4, 4, 0>);
-
- // GL_INT_2_10_10_10_REV
- AddIntegerVertexFormatInfo(&map, GL_INT_2_10_10_10_REV, 4, VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16B16A16_SINT, &CopyXYZ10W2ToXYZW32FVertexData<true, true, false>);
-
- // GL_UNSIGNED_INT_2_10_10_10_REV
- AddIntegerVertexFormatInfo(&map, GL_UNSIGNED_INT_2_10_10_10_REV, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R10G10B10A2_UINT, &CopyNativeVertexData<GLuint, 1, 1, 0>);
+ // GL_UNSIGNED_INT -- un-normalized
+ case gl::VERTEX_FORMAT_UINT1:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R32_UINT, &CopyNativeVertexData<GLuint, 1, 1, 0>);
+ return info;
+ }
+ case gl::VERTEX_FORMAT_UINT2:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R32G32_UINT, &CopyNativeVertexData<GLuint, 2, 2, 0>);
+ return info;
+ }
+ case gl::VERTEX_FORMAT_UINT3:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R32G32B32_UINT, &CopyNativeVertexData<GLuint, 3, 3, 0>);
+ return info;
+ }
+ case gl::VERTEX_FORMAT_UINT4:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R32G32B32A32_UINT, &CopyNativeVertexData<GLuint, 4, 4, 0>);
+ return info;
+ }
- return map;
-}
+ // GL_UNSIGNED_INT -- normalized
+ case gl::VERTEX_FORMAT_UINT1_NORM:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R32_FLOAT, &CopyTo32FVertexData<GLuint, 1, 1, true>);
+ return info;
+ }
+ case gl::VERTEX_FORMAT_UINT2_NORM:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32_FLOAT, &CopyTo32FVertexData<GLuint, 2, 2, true>);
+ return info;
+ }
+ case gl::VERTEX_FORMAT_UINT3_NORM:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32_FLOAT, &CopyTo32FVertexData<GLuint, 3, 3, true>);
+ return info;
+ }
+ case gl::VERTEX_FORMAT_UINT4_NORM:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32B32A32_FLOAT, &CopyTo32FVertexData<GLuint, 4, 4, true>);
+ return info;
+ }
-const VertexFormat &GetVertexFormatInfo(const gl::VertexFormat &vertexFormat, D3D_FEATURE_LEVEL featureLevel)
-{
- static const D3D11VertexFormatInfoMap vertexFormatMap = BuildD3D11VertexFormatInfoMap();
- static const D3D11VertexFormatInfoMap vertexFormatMapFL9_3Override = BuildD3D11_FL9_3VertexFormatInfoOverrideMap();
+ // GL_FIXED
+ case gl::VERTEX_FORMAT_FIXED1:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R32_FLOAT, &Copy32FixedTo32FVertexData<1, 1>);
+ return info;
+ }
+ case gl::VERTEX_FORMAT_FIXED2:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32_FLOAT, &Copy32FixedTo32FVertexData<2, 2>);
+ return info;
+ }
+ case gl::VERTEX_FORMAT_FIXED3:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32_FLOAT, &Copy32FixedTo32FVertexData<3, 3>);
+ return info;
+ }
+ case gl::VERTEX_FORMAT_FIXED4:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32A32_FLOAT, &Copy32FixedTo32FVertexData<4, 4>);
+ return info;
+ }
- if (featureLevel == D3D_FEATURE_LEVEL_9_3)
- {
- // First see if the format has a special mapping for FL9_3
- D3D11VertexFormatInfoMap::const_iterator iter = vertexFormatMapFL9_3Override.find(vertexFormat);
- if (iter != vertexFormatMapFL9_3Override.end())
+ // GL_HALF_FLOAT
+ case gl::VERTEX_FORMAT_HALF1:
{
- return iter->second;
+ static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R16_FLOAT, &CopyNativeVertexData<GLhalf, 1, 1, 0>);
+ return info;
+ }
+ case gl::VERTEX_FORMAT_HALF2:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16_FLOAT, &CopyNativeVertexData<GLhalf, 2, 2, 0>);
+ return info;
+ }
+ case gl::VERTEX_FORMAT_HALF3:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16B16A16_FLOAT, &CopyNativeVertexData<GLhalf, 3, 4, gl::Float16One>);
+ return info;
+ }
+ case gl::VERTEX_FORMAT_HALF4:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16B16A16_FLOAT, &CopyNativeVertexData<GLhalf, 4, 4, 0>);
+ return info;
}
- }
- D3D11VertexFormatInfoMap::const_iterator iter = vertexFormatMap.find(vertexFormat);
- if (iter != vertexFormatMap.end())
- {
- return iter->second;
- }
- else
- {
- static const VertexFormat defaultInfo;
- return defaultInfo;
+ // GL_FLOAT
+ case gl::VERTEX_FORMAT_FLOAT1:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R32_FLOAT, &CopyNativeVertexData<GLfloat, 1, 1, 0>);
+ return info;
+ }
+ case gl::VERTEX_FORMAT_FLOAT2:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32_FLOAT, &CopyNativeVertexData<GLfloat, 2, 2, 0>);
+ return info;
+ }
+ case gl::VERTEX_FORMAT_FLOAT3:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32B32_FLOAT, &CopyNativeVertexData<GLfloat, 3, 3, 0>);
+ return info;
+ }
+ case gl::VERTEX_FORMAT_FLOAT4:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32B32A32_FLOAT, &CopyNativeVertexData<GLfloat, 4, 4, 0>);
+ return info;
+ }
+
+ // GL_INT_2_10_10_10_REV
+ case gl::VERTEX_FORMAT_SINT210:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32A32_FLOAT, &CopyXYZ10W2ToXYZW32FVertexData<true, false, true>);
+ return info;
+ }
+ case gl::VERTEX_FORMAT_SINT210_NORM:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32A32_FLOAT, &CopyXYZ10W2ToXYZW32FVertexData<true, true, true>);
+ return info;
+ }
+
+ // GL_UNSIGNED_INT_2_10_10_10_REV
+ case gl::VERTEX_FORMAT_UINT210:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32A32_FLOAT, &CopyXYZ10W2ToXYZW32FVertexData<false, false, true>);
+ return info;
+ }
+ case gl::VERTEX_FORMAT_UINT210_NORM:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R10G10B10A2_UNORM, &CopyNativeVertexData<GLuint, 1, 1, 0>);
+ return info;
+ }
+
+ //
+ // Integer Formats
+ //
+
+ // GL_BYTE
+ case gl::VERTEX_FORMAT_SBYTE1_INT:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R8_SINT, &CopyNativeVertexData<GLbyte, 1, 1, 0>);
+ return info;
+ }
+ case gl::VERTEX_FORMAT_SBYTE2_INT:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8_SINT, &CopyNativeVertexData<GLbyte, 2, 2, 0>);
+ return info;
+ }
+ case gl::VERTEX_FORMAT_SBYTE3_INT:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R8G8B8A8_SINT, &CopyNativeVertexData<GLbyte, 3, 4, 1>);
+ return info;
+ }
+ case gl::VERTEX_FORMAT_SBYTE4_INT:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8B8A8_SINT, &CopyNativeVertexData<GLbyte, 4, 4, 0>);
+ return info;
+ }
+
+ // GL_UNSIGNED_BYTE
+ case gl::VERTEX_FORMAT_UBYTE1_INT:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R8_UINT, &CopyNativeVertexData<GLubyte, 1, 1, 0>);
+ return info;
+ }
+ case gl::VERTEX_FORMAT_UBYTE2_INT:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8_UINT, &CopyNativeVertexData<GLubyte, 2, 2, 0>);
+ return info;
+ }
+ case gl::VERTEX_FORMAT_UBYTE3_INT:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R8G8B8A8_UINT, &CopyNativeVertexData<GLubyte, 3, 4, 1>);
+ return info;
+ }
+ case gl::VERTEX_FORMAT_UBYTE4_INT:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8B8A8_UINT, &CopyNativeVertexData<GLubyte, 4, 4, 0>);
+ return info;
+ }
+
+ // GL_SHORT
+ case gl::VERTEX_FORMAT_SSHORT1_INT:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R16_SINT, &CopyNativeVertexData<GLshort, 1, 1, 0>);
+ return info;
+ }
+ case gl::VERTEX_FORMAT_SSHORT2_INT:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16_SINT, &CopyNativeVertexData<GLshort, 2, 2, 0>);
+ return info;
+ }
+ case gl::VERTEX_FORMAT_SSHORT3_INT:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16B16A16_SINT, &CopyNativeVertexData<GLshort, 3, 4, 1>);
+ return info;
+ }
+ case gl::VERTEX_FORMAT_SSHORT4_INT:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16B16A16_SINT, &CopyNativeVertexData<GLshort, 4, 4, 0>);
+ return info;
+ }
+
+ // GL_UNSIGNED_SHORT
+ case gl::VERTEX_FORMAT_USHORT1_INT:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R16_UINT, &CopyNativeVertexData<GLushort, 1, 1, 0>);
+ return info;
+ }
+ case gl::VERTEX_FORMAT_USHORT2_INT:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16_UINT, &CopyNativeVertexData<GLushort, 2, 2, 0>);
+ return info;
+ }
+ case gl::VERTEX_FORMAT_USHORT3_INT:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16B16A16_UINT, &CopyNativeVertexData<GLushort, 3, 4, 1>);
+ return info;
+ }
+ case gl::VERTEX_FORMAT_USHORT4_INT:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16B16A16_UINT, &CopyNativeVertexData<GLushort, 4, 4, 0>);
+ return info;
+ }
+
+ // GL_INT
+ case gl::VERTEX_FORMAT_SINT1_INT:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R32_SINT, &CopyNativeVertexData<GLint, 1, 1, 0>);
+ return info;
+ }
+ case gl::VERTEX_FORMAT_SINT2_INT:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32_SINT, &CopyNativeVertexData<GLint, 2, 2, 0>);
+ return info;
+ }
+ case gl::VERTEX_FORMAT_SINT3_INT:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32B32_SINT, &CopyNativeVertexData<GLint, 3, 3, 0>);
+ return info;
+ }
+ case gl::VERTEX_FORMAT_SINT4_INT:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32B32A32_SINT, &CopyNativeVertexData<GLint, 4, 4, 0>);
+ return info;
+ }
+
+ // GL_UNSIGNED_INT
+ case gl::VERTEX_FORMAT_UINT1_INT:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R32_SINT, &CopyNativeVertexData<GLuint, 1, 1, 0>);
+ return info;
+ }
+ case gl::VERTEX_FORMAT_UINT2_INT:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32_SINT, &CopyNativeVertexData<GLuint, 2, 2, 0>);
+ return info;
+ }
+ case gl::VERTEX_FORMAT_UINT3_INT:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32B32_SINT, &CopyNativeVertexData<GLuint, 3, 3, 0>);
+ return info;
+ }
+ case gl::VERTEX_FORMAT_UINT4_INT:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32B32A32_SINT, &CopyNativeVertexData<GLuint, 4, 4, 0>);
+ return info;
+ }
+
+ // GL_INT_2_10_10_10_REV
+ case gl::VERTEX_FORMAT_SINT210_INT:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16B16A16_SINT, &CopyXYZ10W2ToXYZW32FVertexData<true, true, false>);
+ return info;
+ }
+
+ // GL_UNSIGNED_INT_2_10_10_10_REV
+ case gl::VERTEX_FORMAT_UINT210_INT:
+ {
+ static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R10G10B10A2_UINT, &CopyNativeVertexData<GLuint, 1, 1, 0>);
+ return info;
+ }
+
+ default:
+ {
+ static const VertexFormat info;
+ return info;
+ }
}
}
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/formatutils11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/formatutils11.h
index 33fe29dc39..7b97527140 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/formatutils11.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/formatutils11.h
@@ -10,20 +10,22 @@
#ifndef LIBANGLE_RENDERER_D3D_D3D11_FORMATUTILS11_H_
#define LIBANGLE_RENDERER_D3D_D3D11_FORMATUTILS11_H_
-#include "libANGLE/renderer/d3d/formatutilsD3D.h"
-#include "libANGLE/angletypes.h"
+#include <map>
#include "common/platform.h"
-
-#include <map>
+#include "libANGLE/angletypes.h"
+#include "libANGLE/formatutils.h"
+#include "libANGLE/renderer/d3d/formatutilsD3D.h"
namespace rx
{
+struct Renderer11DeviceCaps;
namespace d3d11
{
typedef std::map<std::pair<GLenum, GLenum>, ColorCopyFunction> FastCopyFunctionMap;
+typedef bool (*NativeMipmapGenerationSupportFunction)(D3D_FEATURE_LEVEL);
struct DXGIFormat
{
@@ -51,43 +53,29 @@ struct DXGIFormat
ColorReadFunction colorReadFunction;
FastCopyFunctionMap fastCopyFunctions;
- ColorCopyFunction getFastCopyFunction(GLenum format, GLenum type) const;
-};
-const DXGIFormat &GetDXGIFormatInfo(DXGI_FORMAT format);
-
-struct TextureFormat
-{
- TextureFormat();
- DXGI_FORMAT texFormat;
- DXGI_FORMAT srvFormat;
- DXGI_FORMAT rtvFormat;
- DXGI_FORMAT dsvFormat;
- DXGI_FORMAT renderFormat;
+ NativeMipmapGenerationSupportFunction nativeMipmapSupport;
- DXGI_FORMAT swizzleTexFormat;
- DXGI_FORMAT swizzleSRVFormat;
- DXGI_FORMAT swizzleRTVFormat;
-
- InitializeTextureDataFunction dataInitializerFunction;
-
- typedef std::map<GLenum, LoadImageFunction> LoadFunctionMap;
- LoadFunctionMap loadFunctions;
+ ColorCopyFunction getFastCopyFunction(GLenum format, GLenum type) const;
};
-const TextureFormat &GetTextureFormatInfo(GLenum internalFormat, D3D_FEATURE_LEVEL featureLevel);
+const DXGIFormat &GetDXGIFormatInfo(DXGI_FORMAT format);
struct VertexFormat
{
VertexFormat();
+ VertexFormat(VertexConversionType conversionType,
+ DXGI_FORMAT nativeFormat,
+ VertexCopyFunction copyFunction);
VertexConversionType conversionType;
DXGI_FORMAT nativeFormat;
VertexCopyFunction copyFunction;
};
-const VertexFormat &GetVertexFormatInfo(const gl::VertexFormat &vertexFormat, D3D_FEATURE_LEVEL featureLevel);
+const VertexFormat &GetVertexFormatInfo(gl::VertexFormatType vertexFormatType,
+ D3D_FEATURE_LEVEL featureLevel);
-}
+} // namespace d3d11
-}
+} // namespace rx
#endif // LIBANGLE_RENDERER_D3D_D3D11_FORMATUTILS11_H_
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/gen_load_functions_table.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/gen_load_functions_table.cpp
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/gen_load_functions_table.cpp
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/internal_format_initializer_table.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/internal_format_initializer_table.cpp
new file mode 100644
index 0000000000..adb20a5e60
--- /dev/null
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/internal_format_initializer_table.cpp
@@ -0,0 +1,170 @@
+//
+// 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.
+//
+// internal_format_initializer_table:
+// Contains table to go from internal format and dxgi format to initializer function
+// for TextureFormat
+//
+
+#include "libANGLE/renderer/d3d/d3d11/internal_format_initializer_table.h"
+#include "libANGLE/renderer/d3d/loadimage.h"
+
+namespace rx
+{
+
+namespace d3d11
+{
+
+// TODO: This should be generated by a JSON file
+InitializeTextureDataFunction GetInternalFormatInitializer(GLenum internalFormat,
+ DXGI_FORMAT dxgiFormat)
+{
+ switch (internalFormat)
+ {
+ case GL_RGB8:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_R8G8B8A8_UNORM:
+ {
+ return Initialize4ComponentData<GLubyte, 0x00, 0x00, 0x00, 0xFF>;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_RGB565:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_R8G8B8A8_UNORM:
+ {
+ return Initialize4ComponentData<GLubyte, 0x00, 0x00, 0x00, 0xFF>;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_SRGB8:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
+ {
+ return Initialize4ComponentData<GLubyte, 0x00, 0x00, 0x00, 0xFF>;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_RGB16F:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_R16G16B16A16_FLOAT:
+ {
+ return Initialize4ComponentData<GLhalf, 0x0000, 0x0000, 0x0000, gl::Float16One>;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_RGB32F:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_R32G32B32A32_FLOAT:
+ {
+ return Initialize4ComponentData<GLfloat, 0x00000000, 0x00000000, 0x00000000,
+ gl::Float32One>;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_RGB8UI:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_R8G8B8A8_UINT:
+ {
+ return Initialize4ComponentData<GLubyte, 0x00, 0x00, 0x00, 0x01>;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_RGB8I:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_R8G8B8A8_SINT:
+ {
+ return Initialize4ComponentData<GLbyte, 0x00, 0x00, 0x00, 0x01>;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_RGB16UI:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_R16G16B16A16_UINT:
+ {
+ return Initialize4ComponentData<GLushort, 0x0000, 0x0000, 0x0000, 0x0001>;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_RGB16I:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_R16G16B16A16_SINT:
+ {
+ return Initialize4ComponentData<GLshort, 0x0000, 0x0000, 0x0000, 0x0001>;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_RGB32UI:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_R32G32B32A32_UINT:
+ {
+ return Initialize4ComponentData<GLuint, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000001>;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_RGB32I:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_R32G32B32A32_SINT:
+ {
+ return Initialize4ComponentData<GLint, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000001>;
+ }
+ default:
+ break;
+ }
+ }
+ default:
+ {
+ return nullptr;
+ }
+ }
+}
+
+} // namespace d3d11
+
+} // namespace rx
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/internal_format_initializer_table.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/internal_format_initializer_table.h
new file mode 100644
index 0000000000..2d538e1d82
--- /dev/null
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/internal_format_initializer_table.h
@@ -0,0 +1,31 @@
+//
+// 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.
+//
+// internal_format_initializer_table:
+// Contains table to go from internal format and dxgi format to initializer function
+// for TextureFormat
+//
+
+#ifndef LIBANGLE_RENDERER_D3D_D3D11_INTERNALFORMATINITIALIZERTABLE_H_
+#define LIBANGLE_RENDERER_D3D_D3D11_INTERNALFORMATINITIALIZERTABLE_H_
+
+#include "libANGLE/renderer/d3d/d3d11/Renderer11.h"
+
+#include <map>
+
+namespace rx
+{
+
+namespace d3d11
+{
+
+InitializeTextureDataFunction GetInternalFormatInitializer(GLenum internalFormat,
+ DXGI_FORMAT dxgiFormat);
+
+} // namespace d3d11
+
+} // namespace rx
+
+#endif // LIBANGLE_RENDERER_D3D_D3D11_INTERNALFORMATINITIALIZERTABLE_H_
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/load_functions_data.json b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/load_functions_data.json
new file mode 100644
index 0000000000..c85393e06b
--- /dev/null
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/load_functions_data.json
@@ -0,0 +1,1116 @@
+{
+ "GL_RG8_SNORM": {
+ "GL_BYTE": [
+ {
+ "loadFunction": "LoadToNative<GLbyte,2>",
+ "dxgiFormat": "DXGI_FORMAT_R8G8_SNORM",
+ "requiresConversion": "false"
+ }
+ ]
+ },
+ "GL_SRGB8": {
+ "GL_UNSIGNED_BYTE": [
+ {
+ "loadFunction": "LoadToNative3To4<GLubyte,0xFF>",
+ "dxgiFormat": "DXGI_FORMAT_R8G8B8A8_UNORM_SRGB",
+ "requiresConversion": "true"
+ }
+ ]
+ },
+ "GL_RGBA8I": {
+ "GL_BYTE": [
+ {
+ "loadFunction": "LoadToNative<GLbyte,4>",
+ "dxgiFormat": "DXGI_FORMAT_R8G8B8A8_SINT",
+ "requiresConversion": "false"
+ }
+ ]
+ },
+ "GL_R8_SNORM": {
+ "GL_BYTE": [
+ {
+ "loadFunction": "LoadToNative<GLbyte,1>",
+ "dxgiFormat": "DXGI_FORMAT_R8_SNORM",
+ "requiresConversion": "false"
+ }
+ ]
+ },
+ "GL_RGBA8_SNORM": {
+ "GL_BYTE": [
+ {
+ "loadFunction": "LoadToNative<GLbyte,4>",
+ "dxgiFormat": "DXGI_FORMAT_R8G8B8A8_SNORM",
+ "requiresConversion": "false"
+ }
+ ]
+ },
+ "GL_R16I": {
+ "GL_SHORT": [
+ {
+ "loadFunction": "LoadToNative<GLshort,1>",
+ "dxgiFormat": "DXGI_FORMAT_R16_SINT",
+ "requiresConversion": "false"
+ }
+ ]
+ },
+ "GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC": {
+ "GL_UNSIGNED_BYTE": [
+ {
+ "loadFunction": "LoadETC2SRGBA8ToSRGBA8",
+ "dxgiFormat": "DXGI_FORMAT_R8G8B8A8_UNORM_SRGB",
+ "requiresConversion": "true"
+ }
+ ]
+ },
+ "GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2": {
+ "GL_UNSIGNED_BYTE": [
+ {
+ "loadFunction": "LoadETC2RGB8A1ToRGBA8",
+ "dxgiFormat": "DXGI_FORMAT_R8G8B8A8_UNORM",
+ "requiresConversion": "true"
+ }
+ ]
+ },
+ "GL_RGB32UI": {
+ "GL_UNSIGNED_INT": [
+ {
+ "loadFunction": "LoadToNative3To4<GLuint,0x00000001>",
+ "dxgiFormat": "DXGI_FORMAT_R32G32B32A32_UINT",
+ "requiresConversion": "true"
+ }
+ ]
+ },
+ "GL_ALPHA32F_EXT": {
+ "GL_FLOAT": [
+ {
+ "loadFunction": "LoadA32FToRGBA32F",
+ "dxgiFormat": "DXGI_FORMAT_UNKNOWN",
+ "requiresConversion": "true"
+ }
+ ]
+ },
+ "GL_R16UI": {
+ "GL_UNSIGNED_SHORT": [
+ {
+ "loadFunction": "LoadToNative<GLushort,1>",
+ "dxgiFormat": "DXGI_FORMAT_R16_UINT",
+ "requiresConversion": "false"
+ }
+ ]
+ },
+ "GL_RGB9_E5": {
+ "GL_HALF_FLOAT": [
+ {
+ "loadFunction": "LoadRGB16FToRGB9E5",
+ "dxgiFormat": "DXGI_FORMAT_R9G9B9E5_SHAREDEXP",
+ "requiresConversion": "true"
+ }
+ ],
+ "GL_UNSIGNED_INT_5_9_9_9_REV": [
+ {
+ "loadFunction": "LoadToNative<GLuint,1>",
+ "dxgiFormat": "DXGI_FORMAT_R9G9B9E5_SHAREDEXP",
+ "requiresConversion": "false"
+ }
+ ],
+ "GL_FLOAT": [
+ {
+ "loadFunction": "LoadRGB32FToRGB9E5",
+ "dxgiFormat": "DXGI_FORMAT_R9G9B9E5_SHAREDEXP",
+ "requiresConversion": "true"
+ }
+ ],
+ "GL_HALF_FLOAT_OES": [
+ {
+ "loadFunction": "LoadRGB16FToRGB9E5",
+ "dxgiFormat": "DXGI_FORMAT_R9G9B9E5_SHAREDEXP",
+ "requiresConversion": "true"
+ }
+ ]
+ },
+ "GL_COMPRESSED_R11_EAC": {
+ "GL_UNSIGNED_BYTE": [
+ {
+ "loadFunction": "LoadEACR11ToR8",
+ "dxgiFormat": "DXGI_FORMAT_R8_UNORM",
+ "requiresConversion": "true"
+ }
+ ]
+ },
+ "GL_RGBA32UI": {
+ "GL_UNSIGNED_INT": [
+ {
+ "loadFunction": "LoadToNative<GLuint,4>",
+ "dxgiFormat": "DXGI_FORMAT_R32G32B32A32_UINT",
+ "requiresConversion": "false"
+ }
+ ]
+ },
+ "GL_RG8UI": {
+ "GL_UNSIGNED_BYTE": [
+ {
+ "loadFunction": "LoadToNative<GLubyte,2>",
+ "dxgiFormat": "DXGI_FORMAT_R8G8_UINT",
+ "requiresConversion": "false"
+ }
+ ]
+ },
+ "GL_LUMINANCE32F_EXT": {
+ "GL_FLOAT": [
+ {
+ "loadFunction": "LoadL32FToRGBA32F",
+ "dxgiFormat": "DXGI_FORMAT_UNKNOWN",
+ "requiresConversion": "true"
+ }
+ ]
+ },
+ "GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2": {
+ "GL_UNSIGNED_BYTE": [
+ {
+ "loadFunction": "LoadETC2SRGB8A1ToRGBA8",
+ "dxgiFormat": "DXGI_FORMAT_R8G8B8A8_UNORM_SRGB",
+ "requiresConversion": "true"
+ }
+ ]
+ },
+ "GL_R16F": {
+ "GL_HALF_FLOAT": [
+ {
+ "loadFunction": "LoadToNative<GLhalf,1>",
+ "dxgiFormat": "DXGI_FORMAT_R16_FLOAT",
+ "requiresConversion": "false"
+ }
+ ],
+ "GL_FLOAT": [
+ {
+ "loadFunction": "Load32FTo16F<1>",
+ "dxgiFormat": "DXGI_FORMAT_R16_FLOAT",
+ "requiresConversion": "true"
+ }
+ ],
+ "GL_HALF_FLOAT_OES": [
+ {
+ "loadFunction": "LoadToNative<GLhalf,1>",
+ "dxgiFormat": "DXGI_FORMAT_R16_FLOAT",
+ "requiresConversion": "false"
+ }
+ ]
+ },
+ "GL_RGBA8UI": {
+ "GL_UNSIGNED_BYTE": [
+ {
+ "loadFunction": "LoadToNative<GLubyte,4>",
+ "dxgiFormat": "DXGI_FORMAT_R8G8B8A8_UINT",
+ "requiresConversion": "false"
+ }
+ ]
+ },
+ "GL_BGRA4_ANGLEX": {
+ "GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT": [
+ {
+ "loadFunction": "LoadRGBA4ToRGBA8",
+ "dxgiFormat": "DXGI_FORMAT_UNKNOWN",
+ "requiresConversion": "true"
+ }
+ ],
+ "GL_UNSIGNED_BYTE": [
+ {
+ "loadFunction": "LoadToNative<GLubyte,4>",
+ "dxgiFormat": "DXGI_FORMAT_UNKNOWN",
+ "requiresConversion": "false"
+ }
+ ]
+ },
+ "GL_RGBA16F": {
+ "GL_HALF_FLOAT": [
+ {
+ "loadFunction": "LoadToNative<GLhalf,4>",
+ "dxgiFormat": "DXGI_FORMAT_R16G16B16A16_FLOAT",
+ "requiresConversion": "false"
+ }
+ ],
+ "GL_FLOAT": [
+ {
+ "loadFunction": "Load32FTo16F<4>",
+ "dxgiFormat": "DXGI_FORMAT_R16G16B16A16_FLOAT",
+ "requiresConversion": "true"
+ }
+ ],
+ "GL_HALF_FLOAT_OES": [
+ {
+ "loadFunction": "LoadToNative<GLhalf,4>",
+ "dxgiFormat": "DXGI_FORMAT_R16G16B16A16_FLOAT",
+ "requiresConversion": "false"
+ }
+ ]
+ },
+ "GL_LUMINANCE8_EXT": {
+ "GL_UNSIGNED_BYTE": [
+ {
+ "loadFunction": "LoadL8ToRGBA8",
+ "dxgiFormat": "DXGI_FORMAT_UNKNOWN",
+ "requiresConversion": "true"
+ }
+ ]
+ },
+ "GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE": {
+ "GL_UNSIGNED_BYTE": [
+ {
+ "loadFunction": "LoadCompressedToNative<4,4,16>",
+ "dxgiFormat": "DXGI_FORMAT_UNKNOWN",
+ "requiresConversion": "true"
+ }
+ ]
+ },
+ "GL_RGB": {
+ "GL_UNSIGNED_BYTE": [
+ {
+ "loadFunction": "UnreachableLoadFunction",
+ "dxgiFormat": "DXGI_FORMAT_UNKNOWN",
+ "requiresConversion": "true"
+ }
+ ],
+ "GL_UNSIGNED_SHORT_5_6_5": [
+ {
+ "loadFunction": "UnreachableLoadFunction",
+ "dxgiFormat": "DXGI_FORMAT_UNKNOWN",
+ "requiresConversion": "true"
+ }
+ ]
+ },
+ "GL_RGB5_A1": {
+ "GL_UNSIGNED_INT_2_10_10_10_REV": [
+ {
+ "loadFunction": "LoadRGB10A2ToRGBA8",
+ "dxgiFormat": "DXGI_FORMAT_R8G8B8A8_UNORM",
+ "requiresConversion": "true"
+ }
+ ],
+ "GL_UNSIGNED_BYTE": [
+ {
+ "loadFunction": "LoadToNative<GLubyte,4>",
+ "dxgiFormat": "DXGI_FORMAT_R8G8B8A8_UNORM",
+ "requiresConversion": "false"
+ }
+ ],
+ "GL_UNSIGNED_SHORT_5_5_5_1": [
+ {
+ "loadFunction": "LoadRGB5A1ToRGBA8",
+ "dxgiFormat": "DXGI_FORMAT_R8G8B8A8_UNORM",
+ "requiresConversion": "true"
+ },
+ {
+ "loadFunction": "LoadRGB5A1ToA1RGB5",
+ "dxgiFormat": "DXGI_FORMAT_B5G5R5A1_UNORM",
+ "requiresConversion": "true"
+ }
+ ]
+ },
+ "GL_RGB16UI": {
+ "GL_UNSIGNED_SHORT": [
+ {
+ "loadFunction": "LoadToNative3To4<GLushort,0x0001>",
+ "dxgiFormat": "DXGI_FORMAT_R16G16B16A16_UINT",
+ "requiresConversion": "true"
+ }
+ ]
+ },
+ "GL_BGRA_EXT": {
+ "GL_UNSIGNED_BYTE": [
+ {
+ "loadFunction": "UnreachableLoadFunction",
+ "dxgiFormat": "DXGI_FORMAT_UNKNOWN",
+ "requiresConversion": "true"
+ }
+ ]
+ },
+ "GL_COMPRESSED_RGB8_ETC2": {
+ "GL_UNSIGNED_BYTE": [
+ {
+ "loadFunction": "LoadETC2RGB8ToRGBA8",
+ "dxgiFormat": "DXGI_FORMAT_R8G8B8A8_UNORM",
+ "requiresConversion": "true"
+ }
+ ]
+ },
+ "GL_RGBA32F": {
+ "GL_FLOAT": [
+ {
+ "loadFunction": "LoadToNative<GLfloat,4>",
+ "dxgiFormat": "DXGI_FORMAT_R32G32B32A32_FLOAT",
+ "requiresConversion": "false"
+ }
+ ]
+ },
+ "GL_RGBA32I": {
+ "GL_INT": [
+ {
+ "loadFunction": "LoadToNative<GLint,4>",
+ "dxgiFormat": "DXGI_FORMAT_R32G32B32A32_SINT",
+ "requiresConversion": "false"
+ }
+ ]
+ },
+ "GL_LUMINANCE8_ALPHA8_EXT": {
+ "GL_UNSIGNED_BYTE": [
+ {
+ "loadFunction": "LoadLA8ToRGBA8",
+ "dxgiFormat": "DXGI_FORMAT_UNKNOWN",
+ "requiresConversion": "true"
+ }
+ ]
+ },
+ "GL_RG8": {
+ "GL_UNSIGNED_BYTE": [
+ {
+ "loadFunction": "LoadToNative<GLubyte,2>",
+ "dxgiFormat": "DXGI_FORMAT_R8G8_UNORM",
+ "requiresConversion": "false"
+ }
+ ]
+ },
+ "GL_RGB10_A2": {
+ "GL_UNSIGNED_INT_2_10_10_10_REV": [
+ {
+ "loadFunction": "LoadToNative<GLuint,1>",
+ "dxgiFormat": "DXGI_FORMAT_R10G10B10A2_UNORM",
+ "requiresConversion": "false"
+ }
+ ]
+ },
+ "GL_COMPRESSED_SIGNED_RG11_EAC": {
+ "GL_UNSIGNED_BYTE": [
+ {
+ "loadFunction": "LoadEACRG11SToRG8",
+ "dxgiFormat": "DXGI_FORMAT_R8G8_SNORM",
+ "requiresConversion": "true"
+ }
+ ]
+ },
+ "GL_DEPTH_COMPONENT16": {
+ "GL_UNSIGNED_INT": [
+ {
+ "loadFunction": "LoadR32ToR16",
+ "dxgiFormat": "DXGI_FORMAT_R16_TYPELESS",
+ "requiresConversion": "true"
+ }
+ ],
+ "GL_UNSIGNED_SHORT": [
+ {
+ "loadFunction": "LoadToNative<GLushort,1>",
+ "dxgiFormat": "DXGI_FORMAT_R16_TYPELESS",
+ "requiresConversion": "false"
+ },
+ {
+ "loadFunction": "LoadToNative<GLushort,1>",
+ "dxgiFormat": "DXGI_FORMAT_D16_UNORM",
+ "requiresConversion": "false"
+ }
+ ]
+ },
+ "GL_RGB32I": {
+ "GL_INT": [
+ {
+ "loadFunction": "LoadToNative3To4<GLint,0x00000001>",
+ "dxgiFormat": "DXGI_FORMAT_R32G32B32A32_SINT",
+ "requiresConversion": "true"
+ }
+ ]
+ },
+ "GL_R8": {
+ "GL_UNSIGNED_BYTE": [
+ {
+ "loadFunction": "LoadToNative<GLubyte,1>",
+ "dxgiFormat": "DXGI_FORMAT_R8_UNORM",
+ "requiresConversion": "false"
+ }
+ ]
+ },
+ "GL_RGB32F": {
+ "GL_FLOAT": [
+ {
+ "loadFunction": "LoadToNative3To4<GLfloat,gl::Float32One>",
+ "dxgiFormat": "DXGI_FORMAT_R32G32B32A32_FLOAT",
+ "requiresConversion": "true"
+ }
+ ]
+ },
+ "GL_R11F_G11F_B10F": {
+ "GL_UNSIGNED_INT_10F_11F_11F_REV": [
+ {
+ "loadFunction": "LoadToNative<GLuint,1>",
+ "dxgiFormat": "DXGI_FORMAT_R11G11B10_FLOAT",
+ "requiresConversion": "false"
+ }
+ ],
+ "GL_HALF_FLOAT": [
+ {
+ "loadFunction": "LoadRGB16FToRG11B10F",
+ "dxgiFormat": "DXGI_FORMAT_R11G11B10_FLOAT",
+ "requiresConversion": "true"
+ }
+ ],
+ "GL_FLOAT": [
+ {
+ "loadFunction": "LoadRGB32FToRG11B10F",
+ "dxgiFormat": "DXGI_FORMAT_R11G11B10_FLOAT",
+ "requiresConversion": "true"
+ }
+ ],
+ "GL_HALF_FLOAT_OES": [
+ {
+ "loadFunction": "LoadRGB16FToRG11B10F",
+ "dxgiFormat": "DXGI_FORMAT_R11G11B10_FLOAT",
+ "requiresConversion": "true"
+ }
+ ]
+ },
+ "GL_RGB8": {
+ "GL_UNSIGNED_BYTE": [
+ {
+ "loadFunction": "LoadToNative3To4<GLubyte,0xFF>",
+ "dxgiFormat": "DXGI_FORMAT_R8G8B8A8_UNORM",
+ "requiresConversion": "true"
+ }
+ ]
+ },
+ "GL_LUMINANCE_ALPHA": {
+ "GL_HALF_FLOAT": [
+ {
+ "loadFunction": "LoadLA16FToRGBA16F",
+ "dxgiFormat": "DXGI_FORMAT_R16G16B16A16_FLOAT",
+ "requiresConversion": "true"
+ }
+ ],
+ "GL_UNSIGNED_BYTE": [
+ {
+ "loadFunction": "UnreachableLoadFunction",
+ "dxgiFormat": "DXGI_FORMAT_UNKNOWN",
+ "requiresConversion": "true"
+ }
+ ],
+ "GL_FLOAT": [
+ {
+ "loadFunction": "LoadLA32FToRGBA32F",
+ "dxgiFormat": "DXGI_FORMAT_R32G32B32A32_FLOAT",
+ "requiresConversion": "true"
+ }
+ ],
+ "GL_HALF_FLOAT_OES": [
+ {
+ "loadFunction": "LoadLA16FToRGBA16F",
+ "dxgiFormat": "DXGI_FORMAT_R16G16B16A16_FLOAT",
+ "requiresConversion": "true"
+ }
+ ]
+ },
+ "GL_RGBA16I": {
+ "GL_SHORT": [
+ {
+ "loadFunction": "LoadToNative<GLshort,4>",
+ "dxgiFormat": "DXGI_FORMAT_R16G16B16A16_SINT",
+ "requiresConversion": "false"
+ }
+ ]
+ },
+ "GL_R8I": {
+ "GL_BYTE": [
+ {
+ "loadFunction": "LoadToNative<GLbyte,1>",
+ "dxgiFormat": "DXGI_FORMAT_R8_SINT",
+ "requiresConversion": "false"
+ }
+ ]
+ },
+ "GL_RGB8_SNORM": {
+ "GL_BYTE": [
+ {
+ "loadFunction": "LoadToNative3To4<GLbyte,0x7F>",
+ "dxgiFormat": "DXGI_FORMAT_R8G8B8A8_SNORM",
+ "requiresConversion": "true"
+ }
+ ]
+ },
+ "GL_RG32F": {
+ "GL_FLOAT": [
+ {
+ "loadFunction": "LoadToNative<GLfloat,2>",
+ "dxgiFormat": "DXGI_FORMAT_R32G32_FLOAT",
+ "requiresConversion": "false"
+ }
+ ]
+ },
+ "GL_DEPTH_COMPONENT32F": {
+ "GL_FLOAT": [
+ {
+ "loadFunction": "LoadToNative<GLfloat,1>",
+ "dxgiFormat": "DXGI_FORMAT_R32_TYPELESS",
+ "requiresConversion": "false"
+ },
+ {
+ "loadFunction": "UnimplementedLoadFunction",
+ "dxgiFormat": "DXGI_FORMAT_UNKNOWN",
+ "requiresConversion": "true"
+ }
+ ]
+ },
+ "GL_RG32I": {
+ "GL_INT": [
+ {
+ "loadFunction": "LoadToNative<GLint,2>",
+ "dxgiFormat": "DXGI_FORMAT_R32G32_SINT",
+ "requiresConversion": "false"
+ }
+ ]
+ },
+ "GL_ALPHA8_EXT": {
+ "GL_UNSIGNED_BYTE": [
+ {
+ "loadFunction": "LoadToNative<GLubyte,1>",
+ "dxgiFormat": "DXGI_FORMAT_A8_UNORM",
+ "requiresConversion": "false"
+ },
+ {
+ "loadFunction": "LoadA8ToRGBA8",
+ "dxgiFormat": "DXGI_FORMAT_R8G8B8A8_UNORM",
+ "requiresConversion": "true"
+ }
+ ]
+ },
+ "GL_RG32UI": {
+ "GL_UNSIGNED_INT": [
+ {
+ "loadFunction": "LoadToNative<GLuint,2>",
+ "dxgiFormat": "DXGI_FORMAT_R32G32_UINT",
+ "requiresConversion": "false"
+ }
+ ]
+ },
+ "GL_RGBA16UI": {
+ "GL_UNSIGNED_SHORT": [
+ {
+ "loadFunction": "LoadToNative<GLushort,4>",
+ "dxgiFormat": "DXGI_FORMAT_R16G16B16A16_UINT",
+ "requiresConversion": "false"
+ }
+ ]
+ },
+ "GL_COMPRESSED_RGBA8_ETC2_EAC": {
+ "GL_UNSIGNED_BYTE": [
+ {
+ "loadFunction": "LoadETC2RGBA8ToRGBA8",
+ "dxgiFormat": "DXGI_FORMAT_R8G8B8A8_UNORM",
+ "requiresConversion": "true"
+ }
+ ]
+ },
+ "GL_RGB8I": {
+ "GL_BYTE": [
+ {
+ "loadFunction": "LoadToNative3To4<GLbyte,0x01>",
+ "dxgiFormat": "DXGI_FORMAT_R8G8B8A8_SINT",
+ "requiresConversion": "true"
+ }
+ ]
+ },
+ "GL_COMPRESSED_SRGB8_ETC2": {
+ "GL_UNSIGNED_BYTE": [
+ {
+ "loadFunction": "LoadETC2SRGB8ToRGBA8",
+ "dxgiFormat": "DXGI_FORMAT_R8G8B8A8_UNORM_SRGB",
+ "requiresConversion": "true"
+ }
+ ]
+ },
+ "GL_DEPTH32F_STENCIL8": {
+ "GL_FLOAT_32_UNSIGNED_INT_24_8_REV": [
+ {
+ "loadFunction": "LoadToNative<GLuint,2>",
+ "dxgiFormat": "DXGI_FORMAT_R32G8X24_TYPELESS",
+ "requiresConversion": "false"
+ },
+ {
+ "loadFunction": "UnimplementedLoadFunction",
+ "dxgiFormat": "DXGI_FORMAT_UNKNOWN",
+ "requiresConversion": "true"
+ }
+ ]
+ },
+ "GL_RG8I": {
+ "GL_BYTE": [
+ {
+ "loadFunction": "LoadToNative<GLbyte,2>",
+ "dxgiFormat": "DXGI_FORMAT_R8G8_SINT",
+ "requiresConversion": "false"
+ }
+ ]
+ },
+ "GL_R32UI": {
+ "GL_UNSIGNED_INT": [
+ {
+ "loadFunction": "LoadToNative<GLuint,1>",
+ "dxgiFormat": "DXGI_FORMAT_R32_UINT",
+ "requiresConversion": "false"
+ }
+ ]
+ },
+ "GL_BGR5_A1_ANGLEX": {
+ "GL_UNSIGNED_BYTE": [
+ {
+ "loadFunction": "LoadToNative<GLubyte,4>",
+ "dxgiFormat": "DXGI_FORMAT_UNKNOWN",
+ "requiresConversion": "false"
+ }
+ ],
+ "GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT": [
+ {
+ "loadFunction": "LoadRGB5A1ToRGBA8",
+ "dxgiFormat": "DXGI_FORMAT_UNKNOWN",
+ "requiresConversion": "true"
+ }
+ ]
+ },
+ "GL_COMPRESSED_RG11_EAC": {
+ "GL_UNSIGNED_BYTE": [
+ {
+ "loadFunction": "LoadEACRG11ToRG8",
+ "dxgiFormat": "DXGI_FORMAT_R8G8_UNORM",
+ "requiresConversion": "true"
+ }
+ ]
+ },
+ "GL_SRGB8_ALPHA8": {
+ "GL_UNSIGNED_BYTE": [
+ {
+ "loadFunction": "LoadToNative<GLubyte,4>",
+ "dxgiFormat": "DXGI_FORMAT_R8G8B8A8_UNORM_SRGB",
+ "requiresConversion": "false"
+ }
+ ]
+ },
+ "GL_LUMINANCE_ALPHA16F_EXT": {
+ "GL_HALF_FLOAT": [
+ {
+ "loadFunction": "LoadLA16FToRGBA16F",
+ "dxgiFormat": "DXGI_FORMAT_UNKNOWN",
+ "requiresConversion": "true"
+ }
+ ],
+ "GL_HALF_FLOAT_OES": [
+ {
+ "loadFunction": "LoadLA16FToRGBA16F",
+ "dxgiFormat": "DXGI_FORMAT_UNKNOWN",
+ "requiresConversion": "true"
+ }
+ ]
+ },
+ "GL_RGBA": {
+ "GL_UNSIGNED_BYTE": [
+ {
+ "loadFunction": "UnreachableLoadFunction",
+ "dxgiFormat": "DXGI_FORMAT_UNKNOWN",
+ "requiresConversion": "true"
+ }
+ ],
+ "GL_UNSIGNED_SHORT_4_4_4_4": [
+ {
+ "loadFunction": "UnreachableLoadFunction",
+ "dxgiFormat": "DXGI_FORMAT_UNKNOWN",
+ "requiresConversion": "true"
+ }
+ ],
+ "GL_UNSIGNED_SHORT_5_5_5_1": [
+ {
+ "loadFunction": "UnreachableLoadFunction",
+ "dxgiFormat": "DXGI_FORMAT_UNKNOWN",
+ "requiresConversion": "true"
+ }
+ ]
+ },
+ "GL_DEPTH24_STENCIL8": {
+ "GL_UNSIGNED_INT_24_8": [
+ {
+ "loadFunction": "LoadR32ToR24G8",
+ "dxgiFormat": "DXGI_FORMAT_R24G8_TYPELESS",
+ "requiresConversion": "true"
+ },
+ {
+ "loadFunction": "LoadR32ToR24G8",
+ "dxgiFormat": "DXGI_FORMAT_D24_UNORM_S8_UINT",
+ "requiresConversion": "true"
+ }
+ ]
+ },
+ "GL_RGB16I": {
+ "GL_SHORT": [
+ {
+ "loadFunction": "LoadToNative3To4<GLshort,0x0001>",
+ "dxgiFormat": "DXGI_FORMAT_R16G16B16A16_SINT",
+ "requiresConversion": "true"
+ }
+ ]
+ },
+ "GL_R8UI": {
+ "GL_UNSIGNED_BYTE": [
+ {
+ "loadFunction": "LoadToNative<GLubyte,1>",
+ "dxgiFormat": "DXGI_FORMAT_R8_UINT",
+ "requiresConversion": "false"
+ }
+ ]
+ },
+ "GL_ALPHA": {
+ "GL_HALF_FLOAT": [
+ {
+ "loadFunction": "LoadA16FToRGBA16F",
+ "dxgiFormat": "DXGI_FORMAT_R16G16B16A16_FLOAT",
+ "requiresConversion": "true"
+ }
+ ],
+ "GL_UNSIGNED_BYTE": [
+ {
+ "loadFunction": "UnreachableLoadFunction",
+ "dxgiFormat": "DXGI_FORMAT_UNKNOWN",
+ "requiresConversion": "true"
+ }
+ ],
+ "GL_FLOAT": [
+ {
+ "loadFunction": "LoadA32FToRGBA32F",
+ "dxgiFormat": "DXGI_FORMAT_R32G32B32A32_FLOAT",
+ "requiresConversion": "true"
+ }
+ ],
+ "GL_HALF_FLOAT_OES": [
+ {
+ "loadFunction": "LoadA16FToRGBA16F",
+ "dxgiFormat": "DXGI_FORMAT_R16G16B16A16_FLOAT",
+ "requiresConversion": "true"
+ }
+ ]
+ },
+ "GL_RGB16F": {
+ "GL_HALF_FLOAT": [
+ {
+ "loadFunction": "LoadToNative3To4<GLhalf,gl::Float16One>",
+ "dxgiFormat": "DXGI_FORMAT_R16G16B16A16_FLOAT",
+ "requiresConversion": "true"
+ }
+ ],
+ "GL_FLOAT": [
+ {
+ "loadFunction": "LoadRGB32FToRGBA16F",
+ "dxgiFormat": "DXGI_FORMAT_R16G16B16A16_FLOAT",
+ "requiresConversion": "true"
+ }
+ ],
+ "GL_HALF_FLOAT_OES": [
+ {
+ "loadFunction": "LoadToNative3To4<GLhalf,gl::Float16One>",
+ "dxgiFormat": "DXGI_FORMAT_R16G16B16A16_FLOAT",
+ "requiresConversion": "true"
+ }
+ ]
+ },
+ "GL_COMPRESSED_SIGNED_R11_EAC": {
+ "GL_UNSIGNED_BYTE": [
+ {
+ "loadFunction": "LoadEACR11SToR8",
+ "dxgiFormat": "DXGI_FORMAT_R8_SNORM",
+ "requiresConversion": "true"
+ }
+ ]
+ },
+ "GL_COMPRESSED_RGB_S3TC_DXT1_EXT": {
+ "GL_UNSIGNED_BYTE": [
+ {
+ "loadFunction": "LoadCompressedToNative<4,4,8>",
+ "dxgiFormat": "DXGI_FORMAT_UNKNOWN",
+ "requiresConversion": "true"
+ }
+ ]
+ },
+ "GL_COMPRESSED_RGBA_S3TC_DXT1_EXT": {
+ "GL_UNSIGNED_BYTE": [
+ {
+ "loadFunction": "LoadCompressedToNative<4,4,8>",
+ "dxgiFormat": "DXGI_FORMAT_UNKNOWN",
+ "requiresConversion": "true"
+ }
+ ]
+ },
+ "GL_STENCIL_INDEX8": {
+ "DXGI_FORMAT_R24G8_TYPELESS": [
+ {
+ "loadFunction": "UnimplementedLoadFunction",
+ "dxgiFormat": "DXGI_FORMAT_UNKNOWN",
+ "requiresConversion": "true"
+ }
+ ],
+ "DXGI_FORMAT_D24_UNORM_S8_UINT": [
+ {
+ "loadFunction": "UnimplementedLoadFunction",
+ "dxgiFormat": "DXGI_FORMAT_UNKNOWN",
+ "requiresConversion": "true"
+ }
+ ]
+ },
+ "GL_LUMINANCE_ALPHA32F_EXT": {
+ "GL_FLOAT": [
+ {
+ "loadFunction": "LoadLA32FToRGBA32F",
+ "dxgiFormat": "DXGI_FORMAT_UNKNOWN",
+ "requiresConversion": "true"
+ }
+ ]
+ },
+ "GL_RGB8UI": {
+ "GL_UNSIGNED_BYTE": [
+ {
+ "loadFunction": "LoadToNative3To4<GLubyte,0x01>",
+ "dxgiFormat": "DXGI_FORMAT_R8G8B8A8_UINT",
+ "requiresConversion": "true"
+ }
+ ]
+ },
+ "GL_DEPTH_COMPONENT24": {
+ "GL_UNSIGNED_INT": [
+ {
+ "loadFunction": "LoadR32ToR24G8",
+ "dxgiFormat": "DXGI_FORMAT_R24G8_TYPELESS",
+ "requiresConversion": "true"
+ },
+ {
+ "loadFunction": "LoadR32ToR24G8",
+ "dxgiFormat": "DXGI_FORMAT_D24_UNORM_S8_UINT",
+ "requiresConversion": "true"
+ }
+ ]
+ },
+ "GL_R32I": {
+ "GL_INT": [
+ {
+ "loadFunction": "LoadToNative<GLint,1>",
+ "dxgiFormat": "DXGI_FORMAT_R32_SINT",
+ "requiresConversion": "false"
+ }
+ ]
+ },
+ "GL_DEPTH_COMPONENT32_OES": {
+ "GL_UNSIGNED_INT": [
+ {
+ "loadFunction": "LoadR32ToR24G8",
+ "dxgiFormat": "DXGI_FORMAT_UNKNOWN",
+ "requiresConversion": "true"
+ }
+ ]
+ },
+ "GL_R32F": {
+ "GL_FLOAT": [
+ {
+ "loadFunction": "LoadToNative<GLfloat,1>",
+ "dxgiFormat": "DXGI_FORMAT_R32_FLOAT",
+ "requiresConversion": "false"
+ }
+ ]
+ },
+ "GL_RG16F": {
+ "GL_HALF_FLOAT": [
+ {
+ "loadFunction": "LoadToNative<GLhalf,2>",
+ "dxgiFormat": "DXGI_FORMAT_R16G16_FLOAT",
+ "requiresConversion": "false"
+ }
+ ],
+ "GL_FLOAT": [
+ {
+ "loadFunction": "Load32FTo16F<2>",
+ "dxgiFormat": "DXGI_FORMAT_R16G16_FLOAT",
+ "requiresConversion": "true"
+ }
+ ],
+ "GL_HALF_FLOAT_OES": [
+ {
+ "loadFunction": "LoadToNative<GLhalf,2>",
+ "dxgiFormat": "DXGI_FORMAT_R16G16_FLOAT",
+ "requiresConversion": "false"
+ }
+ ]
+ },
+ "GL_RGB565": {
+ "GL_UNSIGNED_BYTE": [
+ {
+ "loadFunction": "LoadToNative3To4<GLubyte,0xFF>",
+ "dxgiFormat": "DXGI_FORMAT_R8G8B8A8_UNORM",
+ "requiresConversion": "true"
+ }
+ ],
+ "GL_UNSIGNED_SHORT_5_6_5": [
+ {
+ "loadFunction": "LoadR5G6B5ToRGBA8",
+ "dxgiFormat": "DXGI_FORMAT_R8G8B8A8_UNORM",
+ "requiresConversion": "true"
+ },
+ {
+ "loadFunction": "LoadToNative<GLushort,1>",
+ "dxgiFormat": "DXGI_FORMAT_B5G6R5_UNORM",
+ "requiresConversion": "false"
+ }
+ ]
+ },
+ "GL_LUMINANCE16F_EXT": {
+ "GL_HALF_FLOAT": [
+ {
+ "loadFunction": "LoadL16FToRGBA16F",
+ "dxgiFormat": "DXGI_FORMAT_UNKNOWN",
+ "requiresConversion": "true"
+ }
+ ],
+ "GL_HALF_FLOAT_OES": [
+ {
+ "loadFunction": "LoadL16FToRGBA16F",
+ "dxgiFormat": "DXGI_FORMAT_UNKNOWN",
+ "requiresConversion": "true"
+ }
+ ]
+ },
+ "GL_RG16UI": {
+ "GL_UNSIGNED_SHORT": [
+ {
+ "loadFunction": "LoadToNative<GLushort,2>",
+ "dxgiFormat": "DXGI_FORMAT_R16G16_UINT",
+ "requiresConversion": "false"
+ }
+ ]
+ },
+ "GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE": {
+ "GL_UNSIGNED_BYTE": [
+ {
+ "loadFunction": "LoadCompressedToNative<4,4,16>",
+ "dxgiFormat": "DXGI_FORMAT_UNKNOWN",
+ "requiresConversion": "true"
+ }
+ ]
+ },
+ "GL_RG16I": {
+ "GL_SHORT": [
+ {
+ "loadFunction": "LoadToNative<GLshort,2>",
+ "dxgiFormat": "DXGI_FORMAT_R16G16_SINT",
+ "requiresConversion": "false"
+ }
+ ]
+ },
+ "GL_BGRA8_EXT": {
+ "GL_UNSIGNED_BYTE": [
+ {
+ "loadFunction": "LoadToNative<GLubyte,4>",
+ "dxgiFormat": "DXGI_FORMAT_UNKNOWN",
+ "requiresConversion": "false"
+ }
+ ]
+ },
+ "GL_ALPHA16F_EXT": {
+ "GL_HALF_FLOAT": [
+ {
+ "loadFunction": "LoadA16FToRGBA16F",
+ "dxgiFormat": "DXGI_FORMAT_UNKNOWN",
+ "requiresConversion": "true"
+ }
+ ],
+ "GL_HALF_FLOAT_OES": [
+ {
+ "loadFunction": "LoadA16FToRGBA16F",
+ "dxgiFormat": "DXGI_FORMAT_UNKNOWN",
+ "requiresConversion": "true"
+ }
+ ]
+ },
+ "GL_RGBA4": {
+ "GL_UNSIGNED_BYTE": [
+ {
+ "loadFunction": "LoadToNative<GLubyte,4>",
+ "dxgiFormat": "DXGI_FORMAT_R8G8B8A8_UNORM",
+ "requiresConversion": "false"
+ }
+ ],
+ "GL_UNSIGNED_SHORT_4_4_4_4": [
+ {
+ "loadFunction": "LoadRGBA4ToRGBA8",
+ "dxgiFormat": "DXGI_FORMAT_R8G8B8A8_UNORM",
+ "requiresConversion": "true"
+ },
+ {
+ "loadFunction": "LoadRGBA4ToARGB4",
+ "dxgiFormat": "DXGI_FORMAT_B4G4R4A4_UNORM",
+ "requiresConversion": "true"
+ }
+ ]
+ },
+ "GL_RGBA8": {
+ "GL_UNSIGNED_BYTE": [
+ {
+ "loadFunction": "LoadToNative<GLubyte,4>",
+ "dxgiFormat": "DXGI_FORMAT_R8G8B8A8_UNORM",
+ "requiresConversion": "false"
+ }
+ ]
+ },
+ "GL_LUMINANCE": {
+ "GL_HALF_FLOAT": [
+ {
+ "loadFunction": "LoadL16FToRGBA16F",
+ "dxgiFormat": "DXGI_FORMAT_R16G16B16A16_FLOAT",
+ "requiresConversion": "true"
+ }
+ ],
+ "GL_UNSIGNED_BYTE": [
+ {
+ "loadFunction": "UnreachableLoadFunction",
+ "dxgiFormat": "DXGI_FORMAT_UNKNOWN",
+ "requiresConversion": "true"
+ }
+ ],
+ "GL_FLOAT": [
+ {
+ "loadFunction": "LoadL32FToRGBA32F",
+ "dxgiFormat": "DXGI_FORMAT_R32G32B32A32_FLOAT",
+ "requiresConversion": "true"
+ }
+ ],
+ "GL_HALF_FLOAT_OES": [
+ {
+ "loadFunction": "LoadL16FToRGBA16F",
+ "dxgiFormat": "DXGI_FORMAT_R16G16B16A16_FLOAT",
+ "requiresConversion": "true"
+ }
+ ]
+ },
+ "GL_RGB10_A2UI": {
+ "GL_UNSIGNED_INT_2_10_10_10_REV": [
+ {
+ "loadFunction": "LoadToNative<GLuint,1>",
+ "dxgiFormat": "DXGI_FORMAT_R10G10B10A2_UINT",
+ "requiresConversion": "false"
+ }
+ ]
+ },
+ "GL_ETC1_RGB8_OES": {
+ "GL_UNSIGNED_BYTE": [
+ {
+ "loadFunction": "LoadETC1RGB8ToRGBA8",
+ "dxgiFormat": "DXGI_FORMAT_R8G8B8A8_UNORM",
+ "requiresConversion": "true"
+ }
+ ]
+ },
+ "GL_ETC1_RGB8_LOSSY_DECODE_ANGLE": {
+ "GL_UNSIGNED_BYTE": [
+ {
+ "loadFunction": "LoadETC1RGB8ToBC1",
+ "dxgiFormat": "DXGI_FORMAT_BC1_UNORM",
+ "requiresConversion": "true"
+ }
+ ]
+ }
+} \ No newline at end of file
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/load_functions_table.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/load_functions_table.h
new file mode 100644
index 0000000000..b17062f68d
--- /dev/null
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/load_functions_table.h
@@ -0,0 +1,31 @@
+//
+// 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.
+//
+// load_functions_table:
+// Contains load functions table depending on internal format and dxgi format
+//
+
+#ifndef LIBANGLE_RENDERER_D3D_D3D11_LOADFUNCTIONSTABLE_H_
+#define LIBANGLE_RENDERER_D3D_D3D11_LOADFUNCTIONSTABLE_H_
+
+#include <map>
+
+#include "libANGLE/renderer/d3d/d3d11/Renderer11.h"
+#include "libANGLE/renderer/d3d/d3d11/texture_format_table.h"
+
+namespace rx
+{
+
+namespace d3d11
+{
+
+const std::map<GLenum, LoadImageFunctionInfo> &GetLoadFunctionsMap(GLenum internalFormat,
+ DXGI_FORMAT dxgiFormat);
+
+} // namespace d3d11
+
+} // namespace rx
+
+#endif // LIBANGLE_RENDERER_D3D_D3D11_LOADFUNCTIONSTABLE_H_
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/load_functions_table_autogen.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/load_functions_table_autogen.cpp
new file mode 100644
index 0000000000..acb48b9573
--- /dev/null
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/load_functions_table_autogen.cpp
@@ -0,0 +1,2098 @@
+// GENERATED FILE - DO NOT EDIT.
+// Generated by gen_load_functions_table.py using data from load_functions_data.json
+//
+// 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.
+//
+// load_functions_table:
+// Contains the GetLoadFunctionsMap for texture_format_util.h
+//
+
+#include "libANGLE/renderer/d3d/d3d11/load_functions_table.h"
+#include "libANGLE/renderer/d3d/d3d11/formatutils11.h"
+#include "libANGLE/renderer/d3d/d3d11/texture_format_table.h"
+#include "libANGLE/renderer/d3d/loadimage.h"
+#include "libANGLE/renderer/d3d/loadimage_etc.h"
+
+namespace rx
+{
+
+namespace d3d11
+{
+
+namespace
+{
+
+// ES3 image loading functions vary based on:
+// - the GL internal format (supplied to glTex*Image*D)
+// - the GL data type given (supplied to glTex*Image*D)
+// - the target DXGI_FORMAT that the image will be loaded into (which is chosen based on the D3D
+// device's capabilities)
+// This map type determines which loading function to use, based on these three parameters.
+// Source formats and types are taken from Tables 3.2 and 3.3 of the ES 3 spec.
+void UnimplementedLoadFunction(size_t width,
+ size_t height,
+ size_t depth,
+ const uint8_t *input,
+ size_t inputRowPitch,
+ size_t inputDepthPitch,
+ uint8_t *output,
+ size_t outputRowPitch,
+ size_t outputDepthPitch)
+{
+ UNIMPLEMENTED();
+}
+
+void UnreachableLoadFunction(size_t width,
+ size_t height,
+ size_t depth,
+ const uint8_t *input,
+ size_t inputRowPitch,
+ size_t inputDepthPitch,
+ uint8_t *output,
+ size_t outputRowPitch,
+ size_t outputDepthPitch)
+{
+ UNREACHABLE();
+}
+
+} // namespace
+
+// TODO we can replace these maps with more generated code
+const std::map<GLenum, LoadImageFunctionInfo> &GetLoadFunctionsMap(GLenum internalFormat,
+ DXGI_FORMAT dxgiFormat)
+{
+ // clang-format off
+ switch (internalFormat)
+ {
+ case GL_ALPHA:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_R16G16B16A16_FLOAT:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_HALF_FLOAT] = LoadImageFunctionInfo(LoadA16FToRGBA16F, true);
+ loadMap[GL_HALF_FLOAT_OES] = LoadImageFunctionInfo(LoadA16FToRGBA16F, true);
+ loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(UnreachableLoadFunction, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ case DXGI_FORMAT_R32G32B32A32_FLOAT:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_FLOAT] = LoadImageFunctionInfo(LoadA32FToRGBA32F, true);
+ loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(UnreachableLoadFunction, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ case DXGI_FORMAT_UNKNOWN:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(UnreachableLoadFunction, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(UnreachableLoadFunction, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ }
+ }
+ case GL_ALPHA16F_EXT:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_UNKNOWN:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_HALF_FLOAT] = LoadImageFunctionInfo(LoadA16FToRGBA16F, true);
+ loadMap[GL_HALF_FLOAT_OES] = LoadImageFunctionInfo(LoadA16FToRGBA16F, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_HALF_FLOAT] = LoadImageFunctionInfo(LoadA16FToRGBA16F, true);
+ loadMap[GL_HALF_FLOAT_OES] = LoadImageFunctionInfo(LoadA16FToRGBA16F, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ }
+ }
+ case GL_ALPHA32F_EXT:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_UNKNOWN:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_FLOAT] = LoadImageFunctionInfo(LoadA32FToRGBA32F, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_FLOAT] = LoadImageFunctionInfo(LoadA32FToRGBA32F, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ }
+ }
+ case GL_ALPHA8_EXT:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_A8_UNORM:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadToNative<GLubyte,1>, false);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ case DXGI_FORMAT_R8G8B8A8_UNORM:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadA8ToRGBA8, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_BGR5_A1_ANGLEX:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_UNKNOWN:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT] = LoadImageFunctionInfo(LoadRGB5A1ToRGBA8, true);
+ loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadToNative<GLubyte,4>, false);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadToNative<GLubyte,4>, true);
+ loadMap[GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT] = LoadImageFunctionInfo(LoadRGB5A1ToRGBA8, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ }
+ }
+ case GL_BGRA4_ANGLEX:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_UNKNOWN:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT] = LoadImageFunctionInfo(LoadRGBA4ToRGBA8, true);
+ loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadToNative<GLubyte,4>, false);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadToNative<GLubyte,4>, true);
+ loadMap[GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT] = LoadImageFunctionInfo(LoadRGBA4ToRGBA8, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ }
+ }
+ case GL_BGRA8_EXT:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_UNKNOWN:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadToNative<GLubyte,4>, false);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadToNative<GLubyte,4>, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ }
+ }
+ case GL_BGRA_EXT:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_UNKNOWN:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(UnreachableLoadFunction, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(UnreachableLoadFunction, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ }
+ }
+ case GL_COMPRESSED_R11_EAC:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_R8_UNORM:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadEACR11ToR8, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_COMPRESSED_RG11_EAC:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_R8G8_UNORM:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadEACRG11ToRG8, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_COMPRESSED_RGB8_ETC2:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_R8G8B8A8_UNORM:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadETC2RGB8ToRGBA8, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_R8G8B8A8_UNORM:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadETC2RGB8A1ToRGBA8, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_COMPRESSED_RGBA8_ETC2_EAC:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_R8G8B8A8_UNORM:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadETC2RGBA8ToRGBA8, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_UNKNOWN:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadCompressedToNative<4,4,8>, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadCompressedToNative<4,4,8>, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ }
+ }
+ case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_UNKNOWN:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadCompressedToNative<4,4,16>, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadCompressedToNative<4,4,16>, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ }
+ }
+ case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_UNKNOWN:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadCompressedToNative<4,4,16>, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadCompressedToNative<4,4,16>, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ }
+ }
+ case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_UNKNOWN:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadCompressedToNative<4,4,8>, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadCompressedToNative<4,4,8>, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ }
+ }
+ case GL_COMPRESSED_SIGNED_R11_EAC:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_R8_SNORM:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadEACR11SToR8, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_COMPRESSED_SIGNED_RG11_EAC:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_R8G8_SNORM:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadEACRG11SToRG8, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadETC2SRGBA8ToSRGBA8, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_COMPRESSED_SRGB8_ETC2:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadETC2SRGB8ToRGBA8, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadETC2SRGB8A1ToRGBA8, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_DEPTH24_STENCIL8:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_D24_UNORM_S8_UINT:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_INT_24_8] = LoadImageFunctionInfo(LoadR32ToR24G8, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ case DXGI_FORMAT_R24G8_TYPELESS:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_INT_24_8] = LoadImageFunctionInfo(LoadR32ToR24G8, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_DEPTH32F_STENCIL8:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_R32G8X24_TYPELESS:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_FLOAT_32_UNSIGNED_INT_24_8_REV] = LoadImageFunctionInfo(LoadToNative<GLuint,2>, false);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ case DXGI_FORMAT_UNKNOWN:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_FLOAT_32_UNSIGNED_INT_24_8_REV] = LoadImageFunctionInfo(UnimplementedLoadFunction, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_FLOAT_32_UNSIGNED_INT_24_8_REV] = LoadImageFunctionInfo(UnimplementedLoadFunction, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ }
+ }
+ case GL_DEPTH_COMPONENT16:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_D16_UNORM:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_SHORT] = LoadImageFunctionInfo(LoadToNative<GLushort,1>, false);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ case DXGI_FORMAT_R16_TYPELESS:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_INT] = LoadImageFunctionInfo(LoadR32ToR16, true);
+ loadMap[GL_UNSIGNED_SHORT] = LoadImageFunctionInfo(LoadToNative<GLushort,1>, false);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_DEPTH_COMPONENT24:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_D24_UNORM_S8_UINT:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_INT] = LoadImageFunctionInfo(LoadR32ToR24G8, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ case DXGI_FORMAT_R24G8_TYPELESS:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_INT] = LoadImageFunctionInfo(LoadR32ToR24G8, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_DEPTH_COMPONENT32F:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_R32_TYPELESS:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_FLOAT] = LoadImageFunctionInfo(LoadToNative<GLfloat,1>, false);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ case DXGI_FORMAT_UNKNOWN:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_FLOAT] = LoadImageFunctionInfo(UnimplementedLoadFunction, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_FLOAT] = LoadImageFunctionInfo(UnimplementedLoadFunction, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ }
+ }
+ case GL_DEPTH_COMPONENT32_OES:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_UNKNOWN:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_INT] = LoadImageFunctionInfo(LoadR32ToR24G8, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_INT] = LoadImageFunctionInfo(LoadR32ToR24G8, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ }
+ }
+ case GL_ETC1_RGB8_LOSSY_DECODE_ANGLE:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_BC1_UNORM:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadETC1RGB8ToBC1, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_ETC1_RGB8_OES:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_R8G8B8A8_UNORM:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadETC1RGB8ToRGBA8, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_LUMINANCE:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_R16G16B16A16_FLOAT:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_HALF_FLOAT] = LoadImageFunctionInfo(LoadL16FToRGBA16F, true);
+ loadMap[GL_HALF_FLOAT_OES] = LoadImageFunctionInfo(LoadL16FToRGBA16F, true);
+ loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(UnreachableLoadFunction, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ case DXGI_FORMAT_R32G32B32A32_FLOAT:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_FLOAT] = LoadImageFunctionInfo(LoadL32FToRGBA32F, true);
+ loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(UnreachableLoadFunction, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ case DXGI_FORMAT_UNKNOWN:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(UnreachableLoadFunction, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(UnreachableLoadFunction, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ }
+ }
+ case GL_LUMINANCE16F_EXT:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_UNKNOWN:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_HALF_FLOAT] = LoadImageFunctionInfo(LoadL16FToRGBA16F, true);
+ loadMap[GL_HALF_FLOAT_OES] = LoadImageFunctionInfo(LoadL16FToRGBA16F, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_HALF_FLOAT] = LoadImageFunctionInfo(LoadL16FToRGBA16F, true);
+ loadMap[GL_HALF_FLOAT_OES] = LoadImageFunctionInfo(LoadL16FToRGBA16F, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ }
+ }
+ case GL_LUMINANCE32F_EXT:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_UNKNOWN:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_FLOAT] = LoadImageFunctionInfo(LoadL32FToRGBA32F, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_FLOAT] = LoadImageFunctionInfo(LoadL32FToRGBA32F, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ }
+ }
+ case GL_LUMINANCE8_ALPHA8_EXT:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_UNKNOWN:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadLA8ToRGBA8, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadLA8ToRGBA8, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ }
+ }
+ case GL_LUMINANCE8_EXT:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_UNKNOWN:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadL8ToRGBA8, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadL8ToRGBA8, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ }
+ }
+ case GL_LUMINANCE_ALPHA:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_R16G16B16A16_FLOAT:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_HALF_FLOAT] = LoadImageFunctionInfo(LoadLA16FToRGBA16F, true);
+ loadMap[GL_HALF_FLOAT_OES] = LoadImageFunctionInfo(LoadLA16FToRGBA16F, true);
+ loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(UnreachableLoadFunction, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ case DXGI_FORMAT_R32G32B32A32_FLOAT:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_FLOAT] = LoadImageFunctionInfo(LoadLA32FToRGBA32F, true);
+ loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(UnreachableLoadFunction, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ case DXGI_FORMAT_UNKNOWN:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(UnreachableLoadFunction, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(UnreachableLoadFunction, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ }
+ }
+ case GL_LUMINANCE_ALPHA16F_EXT:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_UNKNOWN:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_HALF_FLOAT] = LoadImageFunctionInfo(LoadLA16FToRGBA16F, true);
+ loadMap[GL_HALF_FLOAT_OES] = LoadImageFunctionInfo(LoadLA16FToRGBA16F, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_HALF_FLOAT] = LoadImageFunctionInfo(LoadLA16FToRGBA16F, true);
+ loadMap[GL_HALF_FLOAT_OES] = LoadImageFunctionInfo(LoadLA16FToRGBA16F, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ }
+ }
+ case GL_LUMINANCE_ALPHA32F_EXT:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_UNKNOWN:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_FLOAT] = LoadImageFunctionInfo(LoadLA32FToRGBA32F, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_FLOAT] = LoadImageFunctionInfo(LoadLA32FToRGBA32F, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ }
+ }
+ case GL_R11F_G11F_B10F:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_R11G11B10_FLOAT:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_HALF_FLOAT] = LoadImageFunctionInfo(LoadRGB16FToRG11B10F, true);
+ loadMap[GL_HALF_FLOAT_OES] = LoadImageFunctionInfo(LoadRGB16FToRG11B10F, true);
+ loadMap[GL_FLOAT] = LoadImageFunctionInfo(LoadRGB32FToRG11B10F, true);
+ loadMap[GL_UNSIGNED_INT_10F_11F_11F_REV] = LoadImageFunctionInfo(LoadToNative<GLuint,1>, false);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_R16F:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_R16_FLOAT:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_FLOAT] = LoadImageFunctionInfo(Load32FTo16F<1>, true);
+ loadMap[GL_HALF_FLOAT] = LoadImageFunctionInfo(LoadToNative<GLhalf,1>, false);
+ loadMap[GL_HALF_FLOAT_OES] = LoadImageFunctionInfo(LoadToNative<GLhalf,1>, false);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_R16I:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_R16_SINT:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_SHORT] = LoadImageFunctionInfo(LoadToNative<GLshort,1>, false);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_R16UI:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_R16_UINT:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_SHORT] = LoadImageFunctionInfo(LoadToNative<GLushort,1>, false);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_R32F:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_R32_FLOAT:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_FLOAT] = LoadImageFunctionInfo(LoadToNative<GLfloat,1>, false);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_R32I:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_R32_SINT:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_INT] = LoadImageFunctionInfo(LoadToNative<GLint,1>, false);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_R32UI:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_R32_UINT:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_INT] = LoadImageFunctionInfo(LoadToNative<GLuint,1>, false);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_R8:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_R8_UNORM:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadToNative<GLubyte,1>, false);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_R8I:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_R8_SINT:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_BYTE] = LoadImageFunctionInfo(LoadToNative<GLbyte,1>, false);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_R8UI:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_R8_UINT:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadToNative<GLubyte,1>, false);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_R8_SNORM:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_R8_SNORM:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_BYTE] = LoadImageFunctionInfo(LoadToNative<GLbyte,1>, false);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_RG16F:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_R16G16_FLOAT:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_FLOAT] = LoadImageFunctionInfo(Load32FTo16F<2>, true);
+ loadMap[GL_HALF_FLOAT] = LoadImageFunctionInfo(LoadToNative<GLhalf,2>, false);
+ loadMap[GL_HALF_FLOAT_OES] = LoadImageFunctionInfo(LoadToNative<GLhalf,2>, false);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_RG16I:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_R16G16_SINT:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_SHORT] = LoadImageFunctionInfo(LoadToNative<GLshort,2>, false);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_RG16UI:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_R16G16_UINT:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_SHORT] = LoadImageFunctionInfo(LoadToNative<GLushort,2>, false);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_RG32F:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_R32G32_FLOAT:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_FLOAT] = LoadImageFunctionInfo(LoadToNative<GLfloat,2>, false);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_RG32I:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_R32G32_SINT:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_INT] = LoadImageFunctionInfo(LoadToNative<GLint,2>, false);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_RG32UI:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_R32G32_UINT:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_INT] = LoadImageFunctionInfo(LoadToNative<GLuint,2>, false);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_RG8:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_R8G8_UNORM:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadToNative<GLubyte,2>, false);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_RG8I:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_R8G8_SINT:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_BYTE] = LoadImageFunctionInfo(LoadToNative<GLbyte,2>, false);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_RG8UI:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_R8G8_UINT:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadToNative<GLubyte,2>, false);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_RG8_SNORM:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_R8G8_SNORM:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_BYTE] = LoadImageFunctionInfo(LoadToNative<GLbyte,2>, false);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_RGB:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_UNKNOWN:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(UnreachableLoadFunction, true);
+ loadMap[GL_UNSIGNED_SHORT_5_6_5] = LoadImageFunctionInfo(UnreachableLoadFunction, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(UnreachableLoadFunction, true);
+ loadMap[GL_UNSIGNED_SHORT_5_6_5] = LoadImageFunctionInfo(UnreachableLoadFunction, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ }
+ }
+ case GL_RGB10_A2:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_R10G10B10A2_UNORM:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_INT_2_10_10_10_REV] = LoadImageFunctionInfo(LoadToNative<GLuint,1>, false);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_RGB10_A2UI:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_R10G10B10A2_UINT:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_INT_2_10_10_10_REV] = LoadImageFunctionInfo(LoadToNative<GLuint,1>, false);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_RGB16F:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_R16G16B16A16_FLOAT:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_FLOAT] = LoadImageFunctionInfo(LoadRGB32FToRGBA16F, true);
+ loadMap[GL_HALF_FLOAT] = LoadImageFunctionInfo(LoadToNative3To4<GLhalf,gl::Float16One>, true);
+ loadMap[GL_HALF_FLOAT_OES] = LoadImageFunctionInfo(LoadToNative3To4<GLhalf,gl::Float16One>, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_RGB16I:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_R16G16B16A16_SINT:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_SHORT] = LoadImageFunctionInfo(LoadToNative3To4<GLshort,0x0001>, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_RGB16UI:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_R16G16B16A16_UINT:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_SHORT] = LoadImageFunctionInfo(LoadToNative3To4<GLushort,0x0001>, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_RGB32F:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_R32G32B32A32_FLOAT:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_FLOAT] = LoadImageFunctionInfo(LoadToNative3To4<GLfloat,gl::Float32One>, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_RGB32I:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_R32G32B32A32_SINT:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_INT] = LoadImageFunctionInfo(LoadToNative3To4<GLint,0x00000001>, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_RGB32UI:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_R32G32B32A32_UINT:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_INT] = LoadImageFunctionInfo(LoadToNative3To4<GLuint,0x00000001>, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_RGB565:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_B5G6R5_UNORM:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_SHORT_5_6_5] = LoadImageFunctionInfo(LoadToNative<GLushort,1>, false);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ case DXGI_FORMAT_R8G8B8A8_UNORM:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_SHORT_5_6_5] = LoadImageFunctionInfo(LoadR5G6B5ToRGBA8, true);
+ loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadToNative3To4<GLubyte,0xFF>, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_RGB5_A1:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_B5G5R5A1_UNORM:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_SHORT_5_5_5_1] = LoadImageFunctionInfo(LoadRGB5A1ToA1RGB5, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ case DXGI_FORMAT_R8G8B8A8_UNORM:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_INT_2_10_10_10_REV] = LoadImageFunctionInfo(LoadRGB10A2ToRGBA8, true);
+ loadMap[GL_UNSIGNED_SHORT_5_5_5_1] = LoadImageFunctionInfo(LoadRGB5A1ToRGBA8, true);
+ loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadToNative<GLubyte,4>, false);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_RGB8:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_R8G8B8A8_UNORM:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadToNative3To4<GLubyte,0xFF>, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_RGB8I:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_R8G8B8A8_SINT:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_BYTE] = LoadImageFunctionInfo(LoadToNative3To4<GLbyte,0x01>, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_RGB8UI:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_R8G8B8A8_UINT:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadToNative3To4<GLubyte,0x01>, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_RGB8_SNORM:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_R8G8B8A8_SNORM:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_BYTE] = LoadImageFunctionInfo(LoadToNative3To4<GLbyte,0x7F>, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_RGB9_E5:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_R9G9B9E5_SHAREDEXP:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_HALF_FLOAT] = LoadImageFunctionInfo(LoadRGB16FToRGB9E5, true);
+ loadMap[GL_HALF_FLOAT_OES] = LoadImageFunctionInfo(LoadRGB16FToRGB9E5, true);
+ loadMap[GL_FLOAT] = LoadImageFunctionInfo(LoadRGB32FToRGB9E5, true);
+ loadMap[GL_UNSIGNED_INT_5_9_9_9_REV] = LoadImageFunctionInfo(LoadToNative<GLuint,1>, false);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_RGBA:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_UNKNOWN:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(UnreachableLoadFunction, true);
+ loadMap[GL_UNSIGNED_SHORT_4_4_4_4] = LoadImageFunctionInfo(UnreachableLoadFunction, true);
+ loadMap[GL_UNSIGNED_SHORT_5_5_5_1] = LoadImageFunctionInfo(UnreachableLoadFunction, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(UnreachableLoadFunction, true);
+ loadMap[GL_UNSIGNED_SHORT_4_4_4_4] = LoadImageFunctionInfo(UnreachableLoadFunction, true);
+ loadMap[GL_UNSIGNED_SHORT_5_5_5_1] = LoadImageFunctionInfo(UnreachableLoadFunction, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ }
+ }
+ case GL_RGBA16F:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_R16G16B16A16_FLOAT:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_FLOAT] = LoadImageFunctionInfo(Load32FTo16F<4>, true);
+ loadMap[GL_HALF_FLOAT] = LoadImageFunctionInfo(LoadToNative<GLhalf,4>, false);
+ loadMap[GL_HALF_FLOAT_OES] = LoadImageFunctionInfo(LoadToNative<GLhalf,4>, false);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_RGBA16I:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_R16G16B16A16_SINT:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_SHORT] = LoadImageFunctionInfo(LoadToNative<GLshort,4>, false);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_RGBA16UI:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_R16G16B16A16_UINT:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_SHORT] = LoadImageFunctionInfo(LoadToNative<GLushort,4>, false);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_RGBA32F:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_R32G32B32A32_FLOAT:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_FLOAT] = LoadImageFunctionInfo(LoadToNative<GLfloat,4>, false);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_RGBA32I:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_R32G32B32A32_SINT:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_INT] = LoadImageFunctionInfo(LoadToNative<GLint,4>, false);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_RGBA32UI:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_R32G32B32A32_UINT:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_INT] = LoadImageFunctionInfo(LoadToNative<GLuint,4>, false);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_RGBA4:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_B4G4R4A4_UNORM:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_SHORT_4_4_4_4] = LoadImageFunctionInfo(LoadRGBA4ToARGB4, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ case DXGI_FORMAT_R8G8B8A8_UNORM:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_SHORT_4_4_4_4] = LoadImageFunctionInfo(LoadRGBA4ToRGBA8, true);
+ loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadToNative<GLubyte,4>, false);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_RGBA8:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_R8G8B8A8_UNORM:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadToNative<GLubyte,4>, false);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_RGBA8I:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_R8G8B8A8_SINT:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_BYTE] = LoadImageFunctionInfo(LoadToNative<GLbyte,4>, false);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_RGBA8UI:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_R8G8B8A8_UINT:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadToNative<GLubyte,4>, false);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_RGBA8_SNORM:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_R8G8B8A8_SNORM:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_BYTE] = LoadImageFunctionInfo(LoadToNative<GLbyte,4>, false);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_SRGB8:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadToNative3To4<GLubyte,0xFF>, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_SRGB8_ALPHA8:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadToNative<GLubyte,4>, false);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_STENCIL_INDEX8:
+ {
+ switch (dxgiFormat)
+ {
+ case DXGI_FORMAT_UNKNOWN:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[DXGI_FORMAT_D24_UNORM_S8_UINT] = LoadImageFunctionInfo(UnimplementedLoadFunction, true);
+ loadMap[DXGI_FORMAT_R24G8_TYPELESS] = LoadImageFunctionInfo(UnimplementedLoadFunction, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ default:
+ {
+ static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = []() {
+ std::map<GLenum, LoadImageFunctionInfo> loadMap;
+ loadMap[DXGI_FORMAT_D24_UNORM_S8_UINT] = LoadImageFunctionInfo(UnimplementedLoadFunction, true);
+ loadMap[DXGI_FORMAT_R24G8_TYPELESS] = LoadImageFunctionInfo(UnimplementedLoadFunction, true);
+ return loadMap;
+ }();
+
+ return loadFunctionsMap;
+ }
+ }
+ }
+
+ default:
+ {
+ static std::map<GLenum, LoadImageFunctionInfo> emptyLoadFunctionsMap;
+ return emptyLoadFunctionsMap;
+ }
+ }
+ // clang-format on
+
+} // GetLoadFunctionsMap
+
+} // namespace d3d11
+
+} // namespace rx
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.cpp
index 63085f497f..a1175db9af 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.cpp
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.cpp
@@ -8,17 +8,20 @@
// specific to the D3D11 renderer.
#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h"
+
+#include <algorithm>
+
+#include "common/debug.h"
+#include "libANGLE/formatutils.h"
+#include "libANGLE/Framebuffer.h"
+#include "libANGLE/Program.h"
+#include "libANGLE/renderer/d3d/d3d11/dxgi_support_table.h"
#include "libANGLE/renderer/d3d/d3d11/formatutils11.h"
+#include "libANGLE/renderer/d3d/d3d11/Renderer11.h"
#include "libANGLE/renderer/d3d/d3d11/RenderTarget11.h"
+#include "libANGLE/renderer/d3d/d3d11/texture_format_table.h"
#include "libANGLE/renderer/d3d/FramebufferD3D.h"
-#include "libANGLE/renderer/Workarounds.h"
-#include "libANGLE/formatutils.h"
-#include "libANGLE/Program.h"
-#include "libANGLE/Framebuffer.h"
-
-#include "common/debug.h"
-
-#include <algorithm>
+#include "libANGLE/renderer/d3d/WorkaroundsD3D.h"
#ifndef D3D_FL9_1_DEFAULT_MAX_ANISOTROPY
# define D3D_FL9_1_DEFAULT_MAX_ANISOTROPY 2
@@ -300,23 +303,111 @@ D3D11_QUERY ConvertQueryType(GLenum queryType)
case GL_ANY_SAMPLES_PASSED_EXT:
case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT: return D3D11_QUERY_OCCLUSION;
case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN: return D3D11_QUERY_SO_STATISTICS;
+ case GL_TIME_ELAPSED_EXT:
+ // Two internal queries are also created for begin/end timestamps
+ return D3D11_QUERY_TIMESTAMP_DISJOINT;
default: UNREACHABLE(); return D3D11_QUERY_EVENT;
}
}
-}
-
+} // namespace gl_d3d11
namespace d3d11_gl
{
+namespace
+{
+
+// Helper functor for querying DXGI support. Saves passing the parameters repeatedly.
+class DXGISupportHelper : angle::NonCopyable
+{
+ public:
+ DXGISupportHelper(ID3D11Device *device, D3D_FEATURE_LEVEL featureLevel)
+ : mDevice(device),
+ mFeatureLevel(featureLevel)
+ {
+ }
+
+ bool query(DXGI_FORMAT dxgiFormat, UINT supportMask)
+ {
+ if (dxgiFormat == DXGI_FORMAT_UNKNOWN)
+ return false;
+
+ auto dxgiSupport = d3d11::GetDXGISupport(dxgiFormat, mFeatureLevel);
+
+ UINT supportedBits = dxgiSupport.alwaysSupportedFlags;
+
+ if ((dxgiSupport.optionallySupportedFlags & supportMask) != 0)
+ {
+ UINT formatSupport;
+ if (SUCCEEDED(mDevice->CheckFormatSupport(dxgiFormat, &formatSupport)))
+ {
+ supportedBits |= (formatSupport & supportMask);
+ }
+ else
+ {
+ // TODO(jmadill): find out why we fail this call sometimes in FL9_3
+ // ERR("Error checking format support for format 0x%x", dxgiFormat);
+ }
+ }
+
+ return ((supportedBits & supportMask) == supportMask);
+ }
+
+ private:
+ ID3D11Device *mDevice;
+ D3D_FEATURE_LEVEL mFeatureLevel;
+};
+
+} // anonymous namespace
+
+unsigned int GetReservedVertexUniformVectors(D3D_FEATURE_LEVEL featureLevel)
+{
+ switch (featureLevel)
+ {
+ case D3D_FEATURE_LEVEL_11_1:
+ case D3D_FEATURE_LEVEL_11_0:
+ case D3D_FEATURE_LEVEL_10_1:
+ case D3D_FEATURE_LEVEL_10_0:
+ return 0;
+
+ case D3D_FEATURE_LEVEL_9_3:
+ case D3D_FEATURE_LEVEL_9_2:
+ case D3D_FEATURE_LEVEL_9_1:
+ return 3; // dx_ViewAdjust, dx_ViewCoords and dx_ViewScale
+
+ default:
+ UNREACHABLE();
+ return 0;
+ }
+}
+
+unsigned int GetReservedFragmentUniformVectors(D3D_FEATURE_LEVEL featureLevel)
+{
+ switch (featureLevel)
+ {
+ case D3D_FEATURE_LEVEL_11_1:
+ case D3D_FEATURE_LEVEL_11_0:
+ case D3D_FEATURE_LEVEL_10_1:
+ case D3D_FEATURE_LEVEL_10_0:
+ return 0;
+
+ case D3D_FEATURE_LEVEL_9_3:
+ case D3D_FEATURE_LEVEL_9_2:
+ case D3D_FEATURE_LEVEL_9_1:
+ return 3;
+
+ default:
+ UNREACHABLE();
+ return 0;
+ }
+}
+
GLint GetMaximumClientVersion(D3D_FEATURE_LEVEL featureLevel)
{
switch (featureLevel)
{
-#if defined(ANGLE_ENABLE_D3D11_1)
case D3D_FEATURE_LEVEL_11_1:
-#endif
case D3D_FEATURE_LEVEL_11_0:
case D3D_FEATURE_LEVEL_10_1:
case D3D_FEATURE_LEVEL_10_0: return 3;
@@ -329,52 +420,52 @@ GLint GetMaximumClientVersion(D3D_FEATURE_LEVEL featureLevel)
}
}
-static gl::TextureCaps GenerateTextureFormatCaps(GLint maxClientVersion, GLenum internalFormat, ID3D11Device *device)
+static gl::TextureCaps GenerateTextureFormatCaps(GLint maxClientVersion, GLenum internalFormat, ID3D11Device *device, const Renderer11DeviceCaps &renderer11DeviceCaps)
{
gl::TextureCaps textureCaps;
- const d3d11::TextureFormat &formatInfo = d3d11::GetTextureFormatInfo(internalFormat, device->GetFeatureLevel());
+ DXGISupportHelper support(device, renderer11DeviceCaps.featureLevel);
+ const d3d11::TextureFormat &formatInfo =
+ d3d11::GetTextureFormatInfo(internalFormat, renderer11DeviceCaps);
+
+ const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat);
- UINT formatSupport;
- if (SUCCEEDED(device->CheckFormatSupport(formatInfo.texFormat, &formatSupport)))
+ UINT texSupportMask = D3D11_FORMAT_SUPPORT_TEXTURE2D;
+ if (internalFormatInfo.depthBits == 0 && internalFormatInfo.stencilBits == 0)
{
- const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat);
- if (internalFormatInfo.depthBits > 0 || internalFormatInfo.stencilBits > 0)
+ texSupportMask |= D3D11_FORMAT_SUPPORT_TEXTURECUBE;
+ if (maxClientVersion > 2)
{
- textureCaps.texturable = ((formatSupport & D3D11_FORMAT_SUPPORT_TEXTURE2D) != 0);
- }
- else
- {
- UINT formatSupportMask = D3D11_FORMAT_SUPPORT_TEXTURE2D | D3D11_FORMAT_SUPPORT_TEXTURECUBE;
- if (maxClientVersion > 2)
- {
- formatSupportMask |= D3D11_FORMAT_SUPPORT_TEXTURE3D;
- }
- textureCaps.texturable = ((formatSupport & formatSupportMask) == formatSupportMask);
+ texSupportMask |= D3D11_FORMAT_SUPPORT_TEXTURE3D;
}
}
- if (SUCCEEDED(device->CheckFormatSupport(formatInfo.renderFormat, &formatSupport)) &&
- ((formatSupport & D3D11_FORMAT_SUPPORT_MULTISAMPLE_RENDERTARGET) != 0))
+ textureCaps.texturable = support.query(formatInfo.texFormat, texSupportMask);
+ textureCaps.filterable = support.query(formatInfo.srvFormat, D3D11_FORMAT_SUPPORT_SHADER_SAMPLE);
+ textureCaps.renderable = (support.query(formatInfo.rtvFormat, D3D11_FORMAT_SUPPORT_RENDER_TARGET)) ||
+ (support.query(formatInfo.dsvFormat, D3D11_FORMAT_SUPPORT_DEPTH_STENCIL));
+
+ if (support.query(formatInfo.renderFormat, D3D11_FORMAT_SUPPORT_MULTISAMPLE_RENDERTARGET))
{
- for (size_t sampleCount = 1; sampleCount <= D3D11_MAX_MULTISAMPLE_SAMPLE_COUNT; sampleCount++)
+ // Assume 1x
+ textureCaps.sampleCounts.insert(1);
+
+ for (unsigned int sampleCount = 2; sampleCount <= D3D11_MAX_MULTISAMPLE_SAMPLE_COUNT;
+ sampleCount *= 2)
{
UINT qualityCount = 0;
- if (SUCCEEDED(device->CheckMultisampleQualityLevels(formatInfo.renderFormat, sampleCount, &qualityCount)) &&
- qualityCount > 0)
+ if (SUCCEEDED(device->CheckMultisampleQualityLevels(formatInfo.renderFormat, sampleCount, &qualityCount)))
{
+ // Assume we always support lower sample counts
+ if (qualityCount == 0)
+ {
+ break;
+ }
textureCaps.sampleCounts.insert(sampleCount);
}
}
}
- textureCaps.filterable = SUCCEEDED(device->CheckFormatSupport(formatInfo.srvFormat, &formatSupport)) &&
- ((formatSupport & D3D11_FORMAT_SUPPORT_SHADER_SAMPLE)) != 0;
- textureCaps.renderable = (SUCCEEDED(device->CheckFormatSupport(formatInfo.rtvFormat, &formatSupport)) &&
- ((formatSupport & D3D11_FORMAT_SUPPORT_RENDER_TARGET)) != 0) ||
- (SUCCEEDED(device->CheckFormatSupport(formatInfo.dsvFormat, &formatSupport)) &&
- ((formatSupport & D3D11_FORMAT_SUPPORT_DEPTH_STENCIL) != 0));
-
return textureCaps;
}
@@ -382,9 +473,7 @@ static bool GetNPOTTextureSupport(D3D_FEATURE_LEVEL featureLevel)
{
switch (featureLevel)
{
-#if defined(ANGLE_ENABLE_D3D11_1)
case D3D_FEATURE_LEVEL_11_1:
-#endif
case D3D_FEATURE_LEVEL_11_0:
case D3D_FEATURE_LEVEL_10_1:
case D3D_FEATURE_LEVEL_10_0: return true;
@@ -402,9 +491,7 @@ static float GetMaximumAnisotropy(D3D_FEATURE_LEVEL featureLevel)
{
switch (featureLevel)
{
-#if defined(ANGLE_ENABLE_D3D11_1)
case D3D_FEATURE_LEVEL_11_1:
-#endif
case D3D_FEATURE_LEVEL_11_0: return D3D11_MAX_MAXANISOTROPY;
case D3D_FEATURE_LEVEL_10_1:
@@ -424,9 +511,7 @@ static bool GetOcclusionQuerySupport(D3D_FEATURE_LEVEL featureLevel)
{
switch (featureLevel)
{
-#if defined(ANGLE_ENABLE_D3D11_1)
case D3D_FEATURE_LEVEL_11_1:
-#endif
case D3D_FEATURE_LEVEL_11_0:
case D3D_FEATURE_LEVEL_10_1:
case D3D_FEATURE_LEVEL_10_0: return true;
@@ -446,9 +531,7 @@ static bool GetEventQuerySupport(D3D_FEATURE_LEVEL featureLevel)
switch (featureLevel)
{
-#if defined(ANGLE_ENABLE_D3D11_1)
case D3D_FEATURE_LEVEL_11_1:
-#endif
case D3D_FEATURE_LEVEL_11_0:
case D3D_FEATURE_LEVEL_10_1:
case D3D_FEATURE_LEVEL_10_0:
@@ -466,9 +549,7 @@ static bool GetInstancingSupport(D3D_FEATURE_LEVEL featureLevel)
switch (featureLevel)
{
-#if defined(ANGLE_ENABLE_D3D11_1)
case D3D_FEATURE_LEVEL_11_1:
-#endif
case D3D_FEATURE_LEVEL_11_0:
case D3D_FEATURE_LEVEL_10_1:
case D3D_FEATURE_LEVEL_10_0: return true;
@@ -491,9 +572,7 @@ static bool GetFramebufferMultisampleSupport(D3D_FEATURE_LEVEL featureLevel)
{
switch (featureLevel)
{
-#if defined(ANGLE_ENABLE_D3D11_1)
case D3D_FEATURE_LEVEL_11_1:
-#endif
case D3D_FEATURE_LEVEL_11_0:
case D3D_FEATURE_LEVEL_10_1:
case D3D_FEATURE_LEVEL_10_0: return true;
@@ -510,9 +589,7 @@ static bool GetFramebufferBlitSupport(D3D_FEATURE_LEVEL featureLevel)
{
switch (featureLevel)
{
-#if defined(ANGLE_ENABLE_D3D11_1)
case D3D_FEATURE_LEVEL_11_1:
-#endif
case D3D_FEATURE_LEVEL_11_0:
case D3D_FEATURE_LEVEL_10_1:
case D3D_FEATURE_LEVEL_10_0: return true;
@@ -535,9 +612,7 @@ static bool GetDerivativeInstructionSupport(D3D_FEATURE_LEVEL featureLevel)
switch (featureLevel)
{
-#if defined(ANGLE_ENABLE_D3D11_1)
case D3D_FEATURE_LEVEL_11_1:
-#endif
case D3D_FEATURE_LEVEL_11_0:
case D3D_FEATURE_LEVEL_10_1:
case D3D_FEATURE_LEVEL_10_0:
@@ -553,9 +628,7 @@ static bool GetShaderTextureLODSupport(D3D_FEATURE_LEVEL featureLevel)
{
switch (featureLevel)
{
-#if defined(ANGLE_ENABLE_D3D11_1)
case D3D_FEATURE_LEVEL_11_1:
-#endif
case D3D_FEATURE_LEVEL_11_0:
case D3D_FEATURE_LEVEL_10_1:
case D3D_FEATURE_LEVEL_10_0: return true;
@@ -574,9 +647,7 @@ static size_t GetMaximumSimultaneousRenderTargets(D3D_FEATURE_LEVEL featureLevel
switch (featureLevel)
{
-#if defined(ANGLE_ENABLE_D3D11_1)
case D3D_FEATURE_LEVEL_11_1:
-#endif
case D3D_FEATURE_LEVEL_11_0: return D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT;
case D3D_FEATURE_LEVEL_10_1:
@@ -594,9 +665,7 @@ static size_t GetMaximum2DTextureSize(D3D_FEATURE_LEVEL featureLevel)
{
switch (featureLevel)
{
-#if defined(ANGLE_ENABLE_D3D11_1)
case D3D_FEATURE_LEVEL_11_1:
-#endif
case D3D_FEATURE_LEVEL_11_0: return D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION;
case D3D_FEATURE_LEVEL_10_1:
@@ -654,9 +723,7 @@ static size_t GetMaximum3DTextureSize(D3D_FEATURE_LEVEL featureLevel)
{
switch (featureLevel)
{
-#if defined(ANGLE_ENABLE_D3D11_1)
case D3D_FEATURE_LEVEL_11_1:
-#endif
case D3D_FEATURE_LEVEL_11_0: return D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION;
case D3D_FEATURE_LEVEL_10_1:
@@ -674,9 +741,7 @@ static size_t GetMaximumViewportSize(D3D_FEATURE_LEVEL featureLevel)
{
switch (featureLevel)
{
-#if defined(ANGLE_ENABLE_D3D11_1)
case D3D_FEATURE_LEVEL_11_1:
-#endif
case D3D_FEATURE_LEVEL_11_0: return D3D11_VIEWPORT_BOUNDS_MAX;
case D3D_FEATURE_LEVEL_10_1:
@@ -700,9 +765,7 @@ static size_t GetMaximumDrawIndexedIndexCount(D3D_FEATURE_LEVEL featureLevel)
switch (featureLevel)
{
-#if defined(ANGLE_ENABLE_D3D11_1)
case D3D_FEATURE_LEVEL_11_1:
-#endif
case D3D_FEATURE_LEVEL_11_0:
case D3D_FEATURE_LEVEL_10_1:
case D3D_FEATURE_LEVEL_10_0: return std::numeric_limits<GLint>::max();
@@ -724,9 +787,7 @@ static size_t GetMaximumDrawVertexCount(D3D_FEATURE_LEVEL featureLevel)
switch (featureLevel)
{
-#if defined(ANGLE_ENABLE_D3D11_1)
case D3D_FEATURE_LEVEL_11_1:
-#endif
case D3D_FEATURE_LEVEL_11_0:
case D3D_FEATURE_LEVEL_10_1:
case D3D_FEATURE_LEVEL_10_0: return std::numeric_limits<GLint>::max();
@@ -743,9 +804,7 @@ static size_t GetMaximumVertexInputSlots(D3D_FEATURE_LEVEL featureLevel)
{
switch (featureLevel)
{
-#if defined(ANGLE_ENABLE_D3D11_1)
case D3D_FEATURE_LEVEL_11_1:
-#endif
case D3D_FEATURE_LEVEL_11_0: return D3D11_STANDARD_VERTEX_ELEMENT_COUNT;
case D3D_FEATURE_LEVEL_10_1: return D3D10_1_STANDARD_VERTEX_ELEMENT_COUNT;
@@ -765,9 +824,7 @@ static size_t GetMaximumVertexUniformVectors(D3D_FEATURE_LEVEL featureLevel)
// TODO(geofflang): Remove hard-coded limit once the gl-uniform-arrays test can pass
switch (featureLevel)
{
-#if defined(ANGLE_ENABLE_D3D11_1)
case D3D_FEATURE_LEVEL_11_1:
-#endif
case D3D_FEATURE_LEVEL_11_0: return 1024; // D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT;
case D3D_FEATURE_LEVEL_10_1:
@@ -776,7 +833,8 @@ static size_t GetMaximumVertexUniformVectors(D3D_FEATURE_LEVEL featureLevel)
// From http://msdn.microsoft.com/en-us/library/windows/desktop/ff476149.aspx ID3D11DeviceContext::VSSetConstantBuffers
case D3D_FEATURE_LEVEL_9_3:
case D3D_FEATURE_LEVEL_9_2:
- case D3D_FEATURE_LEVEL_9_1: return 255;
+ case D3D_FEATURE_LEVEL_9_1:
+ return 255 - d3d11_gl::GetReservedVertexUniformVectors(featureLevel);
default: UNREACHABLE(); return 0;
}
@@ -792,9 +850,7 @@ static size_t GetMaximumVertexUniformBlocks(D3D_FEATURE_LEVEL featureLevel)
{
switch (featureLevel)
{
-#if defined(ANGLE_ENABLE_D3D11_1)
case D3D_FEATURE_LEVEL_11_1:
-#endif
case D3D_FEATURE_LEVEL_11_0: return D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - GetReservedVertexUniformBuffers();
case D3D_FEATURE_LEVEL_10_1:
@@ -822,9 +878,7 @@ static size_t GetReservedVertexOutputVectors(D3D_FEATURE_LEVEL featureLevel)
// We must reserve one output vector for dx_Position.
// We also reserve one for gl_Position, which we unconditionally output on Feature Levels 10_0+,
// even if it's unused in the shader (e.g. for transform feedback). TODO: This could be improved.
-#if defined(ANGLE_ENABLE_D3D11_1)
case D3D_FEATURE_LEVEL_11_1:
-#endif
case D3D_FEATURE_LEVEL_11_0:
case D3D_FEATURE_LEVEL_10_1:
case D3D_FEATURE_LEVEL_10_0: return 2;
@@ -846,9 +900,7 @@ static size_t GetMaximumVertexOutputVectors(D3D_FEATURE_LEVEL featureLevel)
switch (featureLevel)
{
-#if defined(ANGLE_ENABLE_D3D11_1)
case D3D_FEATURE_LEVEL_11_1:
-#endif
case D3D_FEATURE_LEVEL_11_0: return D3D11_VS_OUTPUT_REGISTER_COUNT - GetReservedVertexOutputVectors(featureLevel);
case D3D_FEATURE_LEVEL_10_1: return D3D10_1_VS_OUTPUT_REGISTER_COUNT - GetReservedVertexOutputVectors(featureLevel);
@@ -867,9 +919,7 @@ static size_t GetMaximumVertexTextureUnits(D3D_FEATURE_LEVEL featureLevel)
{
switch (featureLevel)
{
-#if defined(ANGLE_ENABLE_D3D11_1)
case D3D_FEATURE_LEVEL_11_1:
-#endif
case D3D_FEATURE_LEVEL_11_0: return D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT;
case D3D_FEATURE_LEVEL_10_1:
@@ -891,9 +941,7 @@ static size_t GetMaximumPixelUniformVectors(D3D_FEATURE_LEVEL featureLevel)
// TODO(geofflang): Remove hard-coded limit once the gl-uniform-arrays test can pass
switch (featureLevel)
{
-#if defined(ANGLE_ENABLE_D3D11_1)
case D3D_FEATURE_LEVEL_11_1:
-#endif
case D3D_FEATURE_LEVEL_11_0: return 1024; // D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT;
case D3D_FEATURE_LEVEL_10_1:
@@ -902,7 +950,8 @@ static size_t GetMaximumPixelUniformVectors(D3D_FEATURE_LEVEL featureLevel)
// From http://msdn.microsoft.com/en-us/library/windows/desktop/ff476149.aspx ID3D11DeviceContext::PSSetConstantBuffers
case D3D_FEATURE_LEVEL_9_3:
case D3D_FEATURE_LEVEL_9_2:
- case D3D_FEATURE_LEVEL_9_1: return 32;
+ case D3D_FEATURE_LEVEL_9_1:
+ return 32 - d3d11_gl::GetReservedFragmentUniformVectors(featureLevel);
default: UNREACHABLE(); return 0;
}
@@ -918,9 +967,7 @@ static size_t GetMaximumPixelUniformBlocks(D3D_FEATURE_LEVEL featureLevel)
{
switch (featureLevel)
{
-#if defined(ANGLE_ENABLE_D3D11_1)
case D3D_FEATURE_LEVEL_11_1:
-#endif
case D3D_FEATURE_LEVEL_11_0: return D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - GetReservedPixelUniformBuffers();
case D3D_FEATURE_LEVEL_10_1:
@@ -939,9 +986,7 @@ static size_t GetMaximumPixelInputVectors(D3D_FEATURE_LEVEL featureLevel)
{
switch (featureLevel)
{
-#if defined(ANGLE_ENABLE_D3D11_1)
case D3D_FEATURE_LEVEL_11_1:
-#endif
case D3D_FEATURE_LEVEL_11_0: return D3D11_PS_INPUT_REGISTER_COUNT - GetReservedVertexOutputVectors(featureLevel);
case D3D_FEATURE_LEVEL_10_1:
@@ -960,9 +1005,7 @@ static size_t GetMaximumPixelTextureUnits(D3D_FEATURE_LEVEL featureLevel)
{
switch (featureLevel)
{
-#if defined(ANGLE_ENABLE_D3D11_1)
case D3D_FEATURE_LEVEL_11_1:
-#endif
case D3D_FEATURE_LEVEL_11_0: return D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT;
case D3D_FEATURE_LEVEL_10_1:
@@ -981,9 +1024,7 @@ static int GetMinimumTexelOffset(D3D_FEATURE_LEVEL featureLevel)
{
switch (featureLevel)
{
-#if defined(ANGLE_ENABLE_D3D11_1)
case D3D_FEATURE_LEVEL_11_1:
-#endif
case D3D_FEATURE_LEVEL_11_0: return D3D11_COMMONSHADER_TEXEL_OFFSET_MAX_NEGATIVE;
case D3D_FEATURE_LEVEL_10_1:
@@ -1002,9 +1043,7 @@ static int GetMaximumTexelOffset(D3D_FEATURE_LEVEL featureLevel)
{
switch (featureLevel)
{
-#if defined(ANGLE_ENABLE_D3D11_1)
case D3D_FEATURE_LEVEL_11_1:
-#endif
case D3D_FEATURE_LEVEL_11_0: return D3D11_COMMONSHADER_TEXEL_OFFSET_MAX_POSITIVE;
case D3D_FEATURE_LEVEL_10_1:
case D3D_FEATURE_LEVEL_10_0: return D3D11_COMMONSHADER_TEXEL_OFFSET_MAX_POSITIVE;
@@ -1027,9 +1066,7 @@ static size_t GetMaximumConstantBufferSize(D3D_FEATURE_LEVEL featureLevel)
switch (featureLevel)
{
-#if defined(ANGLE_ENABLE_D3D11_1)
case D3D_FEATURE_LEVEL_11_1:
-#endif
case D3D_FEATURE_LEVEL_11_0: return D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT * bytesPerComponent;
case D3D_FEATURE_LEVEL_10_1:
@@ -1048,9 +1085,7 @@ static size_t GetMaximumStreamOutputBuffers(D3D_FEATURE_LEVEL featureLevel)
{
switch (featureLevel)
{
-#if defined(ANGLE_ENABLE_D3D11_1)
case D3D_FEATURE_LEVEL_11_1:
-#endif
case D3D_FEATURE_LEVEL_11_0: return D3D11_SO_BUFFER_SLOT_COUNT;
case D3D_FEATURE_LEVEL_10_1: return D3D10_1_SO_BUFFER_SLOT_COUNT;
@@ -1068,9 +1103,7 @@ static size_t GetMaximumStreamOutputInterleavedComponents(D3D_FEATURE_LEVEL feat
{
switch (featureLevel)
{
-#if defined(ANGLE_ENABLE_D3D11_1)
case D3D_FEATURE_LEVEL_11_1:
-#endif
case D3D_FEATURE_LEVEL_11_0:
case D3D_FEATURE_LEVEL_10_1:
@@ -1088,9 +1121,7 @@ static size_t GetMaximumStreamOutputSeparateComponents(D3D_FEATURE_LEVEL feature
{
switch (featureLevel)
{
-#if defined(ANGLE_ENABLE_D3D11_1)
case D3D_FEATURE_LEVEL_11_1:
-#endif
case D3D_FEATURE_LEVEL_11_0: return GetMaximumStreamOutputInterleavedComponents(featureLevel) /
GetMaximumStreamOutputBuffers(featureLevel);
@@ -1107,15 +1138,15 @@ static size_t GetMaximumStreamOutputSeparateComponents(D3D_FEATURE_LEVEL feature
}
}
-void GenerateCaps(ID3D11Device *device, ID3D11DeviceContext *deviceContext, gl::Caps *caps, gl::TextureCapsMap *textureCapsMap, gl::Extensions *extensions)
+void GenerateCaps(ID3D11Device *device, ID3D11DeviceContext *deviceContext, const Renderer11DeviceCaps &renderer11DeviceCaps, gl::Caps *caps,
+ gl::TextureCapsMap *textureCapsMap, gl::Extensions *extensions, gl::Limitations *limitations)
{
- D3D_FEATURE_LEVEL featureLevel = device->GetFeatureLevel();
-
GLuint maxSamples = 0;
+ D3D_FEATURE_LEVEL featureLevel = renderer11DeviceCaps.featureLevel;
const gl::FormatSet &allFormats = gl::GetAllSizedInternalFormats();
for (gl::FormatSet::const_iterator internalFormat = allFormats.begin(); internalFormat != allFormats.end(); ++internalFormat)
{
- gl::TextureCaps textureCaps = GenerateTextureFormatCaps(GetMaximumClientVersion(featureLevel), *internalFormat, device);
+ gl::TextureCaps textureCaps = GenerateTextureFormatCaps(GetMaximumClientVersion(featureLevel), *internalFormat, device, renderer11DeviceCaps);
textureCapsMap->insert(*internalFormat, textureCaps);
maxSamples = std::max(maxSamples, textureCaps.getMaxSamples());
@@ -1127,11 +1158,12 @@ void GenerateCaps(ID3D11Device *device, ID3D11DeviceContext *deviceContext, gl::
}
// GL core feature limits
- caps->maxElementIndex = static_cast<GLint64>(std::numeric_limits<unsigned int>::max());
- caps->max3DTextureSize = GetMaximum3DTextureSize(featureLevel);
- caps->max2DTextureSize = GetMaximum2DTextureSize(featureLevel);
- caps->maxCubeMapTextureSize = GetMaximumCubeMapTextureSize(featureLevel);
- caps->maxArrayTextureLayers = GetMaximum2DTextureArraySize(featureLevel);
+ // Reserve MAX_UINT for D3D11's primitive restart.
+ caps->maxElementIndex = static_cast<GLint64>(std::numeric_limits<unsigned int>::max() - 1);
+ caps->max3DTextureSize = static_cast<GLuint>(GetMaximum3DTextureSize(featureLevel));
+ caps->max2DTextureSize = static_cast<GLuint>(GetMaximum2DTextureSize(featureLevel));
+ caps->maxCubeMapTextureSize = static_cast<GLuint>(GetMaximumCubeMapTextureSize(featureLevel));
+ caps->maxArrayTextureLayers = static_cast<GLuint>(GetMaximum2DTextureArraySize(featureLevel));
// Unimplemented, set to minimum required
caps->maxLODBias = 2.0f;
@@ -1141,11 +1173,12 @@ void GenerateCaps(ID3D11Device *device, ID3D11DeviceContext *deviceContext, gl::
// Maximum draw buffers and color attachments are the same, max color attachments could eventually be
// increased to 16
- caps->maxDrawBuffers = GetMaximumSimultaneousRenderTargets(featureLevel);
- caps->maxColorAttachments = GetMaximumSimultaneousRenderTargets(featureLevel);
+ caps->maxDrawBuffers = static_cast<GLuint>(GetMaximumSimultaneousRenderTargets(featureLevel));
+ caps->maxColorAttachments =
+ static_cast<GLuint>(GetMaximumSimultaneousRenderTargets(featureLevel));
// D3D11 has the same limit for viewport width and height
- caps->maxViewportWidth = GetMaximumViewportSize(featureLevel);
+ caps->maxViewportWidth = static_cast<GLuint>(GetMaximumViewportSize(featureLevel));
caps->maxViewportHeight = caps->maxViewportWidth;
// Choose a reasonable maximum, enforced in the shader.
@@ -1157,8 +1190,8 @@ void GenerateCaps(ID3D11Device *device, ID3D11DeviceContext *deviceContext, gl::
caps->maxAliasedLineWidth = 1.0f;
// Primitive count limits
- caps->maxElementsIndices = GetMaximumDrawIndexedIndexCount(featureLevel);
- caps->maxElementsVertices = GetMaximumDrawVertexCount(featureLevel);
+ caps->maxElementsIndices = static_cast<GLuint>(GetMaximumDrawIndexedIndexCount(featureLevel));
+ caps->maxElementsVertices = static_cast<GLuint>(GetMaximumDrawVertexCount(featureLevel));
// Program and shader binary formats (no supported shader binary formats)
caps->programBinaryFormats.push_back(GL_PROGRAM_BINARY_ANGLE);
@@ -1182,19 +1215,27 @@ void GenerateCaps(ID3D11Device *device, ID3D11DeviceContext *deviceContext, gl::
caps->maxServerWaitTimeout = 0;
// Vertex shader limits
- caps->maxVertexAttributes = GetMaximumVertexInputSlots(featureLevel);
- caps->maxVertexUniformComponents = GetMaximumVertexUniformVectors(featureLevel) * 4;
- caps->maxVertexUniformVectors = GetMaximumVertexUniformVectors(featureLevel);
- caps->maxVertexUniformBlocks = GetMaximumVertexUniformBlocks(featureLevel);
- caps->maxVertexOutputComponents = GetMaximumVertexOutputVectors(featureLevel) * 4;
- caps->maxVertexTextureImageUnits = GetMaximumVertexTextureUnits(featureLevel);
+ caps->maxVertexAttributes = static_cast<GLuint>(GetMaximumVertexInputSlots(featureLevel));
+ caps->maxVertexUniformComponents =
+ static_cast<GLuint>(GetMaximumVertexUniformVectors(featureLevel)) * 4;
+ caps->maxVertexUniformVectors =
+ static_cast<GLuint>(GetMaximumVertexUniformVectors(featureLevel));
+ caps->maxVertexUniformBlocks = static_cast<GLuint>(GetMaximumVertexUniformBlocks(featureLevel));
+ caps->maxVertexOutputComponents =
+ static_cast<GLuint>(GetMaximumVertexOutputVectors(featureLevel)) * 4;
+ caps->maxVertexTextureImageUnits =
+ static_cast<GLuint>(GetMaximumVertexTextureUnits(featureLevel));
// Fragment shader limits
- caps->maxFragmentUniformComponents = GetMaximumPixelUniformVectors(featureLevel) * 4;
- caps->maxFragmentUniformVectors = GetMaximumPixelUniformVectors(featureLevel);
- caps->maxFragmentUniformBlocks = GetMaximumPixelUniformBlocks(featureLevel);
- caps->maxFragmentInputComponents = GetMaximumPixelInputVectors(featureLevel) * 4;
- caps->maxTextureImageUnits = GetMaximumPixelTextureUnits(featureLevel);
+ caps->maxFragmentUniformComponents =
+ static_cast<GLuint>(GetMaximumPixelUniformVectors(featureLevel)) * 4;
+ caps->maxFragmentUniformVectors =
+ static_cast<GLuint>(GetMaximumPixelUniformVectors(featureLevel));
+ caps->maxFragmentUniformBlocks =
+ static_cast<GLuint>(GetMaximumPixelUniformBlocks(featureLevel));
+ caps->maxFragmentInputComponents =
+ static_cast<GLuint>(GetMaximumPixelInputVectors(featureLevel)) * 4;
+ caps->maxTextureImageUnits = static_cast<GLuint>(GetMaximumPixelTextureUnits(featureLevel));
caps->minProgramTexelOffset = GetMinimumTexelOffset(featureLevel);
caps->maxProgramTexelOffset = GetMaximumTexelOffset(featureLevel);
@@ -1202,45 +1243,36 @@ void GenerateCaps(ID3D11Device *device, ID3D11DeviceContext *deviceContext, gl::
caps->maxUniformBufferBindings = caps->maxVertexUniformBlocks + caps->maxFragmentUniformBlocks;
caps->maxUniformBlockSize = GetMaximumConstantBufferSize(featureLevel);
- // Setting a large alignment forces uniform buffers to bind with zero offset
- caps->uniformBufferOffsetAlignment = static_cast<GLuint>(std::numeric_limits<GLint>::max());
-#if defined(ANGLE_ENABLE_D3D11_1)
- ID3D11DeviceContext1 *deviceContext1 = d3d11::DynamicCastComObject<ID3D11DeviceContext1>(deviceContext);
-
- if (deviceContext1)
- {
- D3D11_FEATURE_DATA_D3D11_OPTIONS d3d11Options;
- device->CheckFeatureSupport(D3D11_FEATURE_D3D11_OPTIONS, &d3d11Options, sizeof(D3D11_FEATURE_DATA_D3D11_OPTIONS));
-
- if (d3d11Options.ConstantBufferOffsetting)
- {
- // With DirectX 11.1, constant buffer offset and size must be a multiple of 16 constants of 16 bytes each.
- // https://msdn.microsoft.com/en-us/library/windows/desktop/hh404649%28v=vs.85%29.aspx
- caps->uniformBufferOffsetAlignment = 256;
- }
-
- SafeRelease(deviceContext1);
- }
-#endif
+ // With DirectX 11.1, constant buffer offset and size must be a multiple of 16 constants of 16 bytes each.
+ // https://msdn.microsoft.com/en-us/library/windows/desktop/hh404649%28v=vs.85%29.aspx
+ // With DirectX 11.0, we emulate UBO offsets using copies of ranges of the UBO however
+ // we still keep the same alignment as 11.1 for consistency.
+ caps->uniformBufferOffsetAlignment = 256;
caps->maxCombinedUniformBlocks = caps->maxVertexUniformBlocks + caps->maxFragmentUniformBlocks;
caps->maxCombinedVertexUniformComponents = (static_cast<GLint64>(caps->maxVertexUniformBlocks) * static_cast<GLint64>(caps->maxUniformBlockSize / 4)) +
static_cast<GLint64>(caps->maxVertexUniformComponents);
caps->maxCombinedFragmentUniformComponents = (static_cast<GLint64>(caps->maxFragmentUniformBlocks) * static_cast<GLint64>(caps->maxUniformBlockSize / 4)) +
static_cast<GLint64>(caps->maxFragmentUniformComponents);
- caps->maxVaryingComponents = GetMaximumVertexOutputVectors(featureLevel) * 4;
- caps->maxVaryingVectors = GetMaximumVertexOutputVectors(featureLevel);
+ caps->maxVaryingComponents =
+ static_cast<GLuint>(GetMaximumVertexOutputVectors(featureLevel)) * 4;
+ caps->maxVaryingVectors = static_cast<GLuint>(GetMaximumVertexOutputVectors(featureLevel));
caps->maxCombinedTextureImageUnits = caps->maxVertexTextureImageUnits + caps->maxTextureImageUnits;
// Transform feedback limits
- caps->maxTransformFeedbackInterleavedComponents = GetMaximumStreamOutputInterleavedComponents(featureLevel);
- caps->maxTransformFeedbackSeparateAttributes = GetMaximumStreamOutputBuffers(featureLevel);
- caps->maxTransformFeedbackSeparateComponents = GetMaximumStreamOutputSeparateComponents(featureLevel);
+ caps->maxTransformFeedbackInterleavedComponents =
+ static_cast<GLuint>(GetMaximumStreamOutputInterleavedComponents(featureLevel));
+ caps->maxTransformFeedbackSeparateAttributes =
+ static_cast<GLuint>(GetMaximumStreamOutputBuffers(featureLevel));
+ caps->maxTransformFeedbackSeparateComponents =
+ static_cast<GLuint>(GetMaximumStreamOutputSeparateComponents(featureLevel));
+
+ // Multisample limits
+ caps->maxSamples = maxSamples;
// GL extension support
extensions->setTextureExtensionSupport(*textureCapsMap);
extensions->elementIndexUint = true;
- extensions->packedDepthStencil = true;
extensions->getProgramBinary = true;
extensions->rgb8rgba8 = true;
extensions->readFormatBGRA = true;
@@ -1255,25 +1287,136 @@ void GenerateCaps(ID3D11Device *device, ID3D11DeviceContext *deviceContext, gl::
extensions->occlusionQueryBoolean = GetOcclusionQuerySupport(featureLevel);
extensions->fence = GetEventQuerySupport(featureLevel);
extensions->timerQuery = false; // Unimplemented
+ extensions->disjointTimerQuery = true;
+ extensions->queryCounterBitsTimeElapsed = 64;
+ extensions->queryCounterBitsTimestamp =
+ 0; // Timestamps cannot be supported due to D3D11 limitations
extensions->robustness = true;
extensions->blendMinMax = true;
extensions->framebufferBlit = GetFramebufferBlitSupport(featureLevel);
extensions->framebufferMultisample = GetFramebufferMultisampleSupport(featureLevel);
- extensions->maxSamples = maxSamples;
extensions->instancedArrays = GetInstancingSupport(featureLevel);
extensions->packReverseRowOrder = true;
extensions->standardDerivatives = GetDerivativeInstructionSupport(featureLevel);
extensions->shaderTextureLOD = GetShaderTextureLODSupport(featureLevel);
extensions->fragDepth = true;
extensions->textureUsage = true; // This could be false since it has no effect in D3D11
+ extensions->discardFramebuffer = true;
extensions->translatedShaderSource = true;
+ extensions->fboRenderMipmap = false;
+ extensions->debugMarker = true;
+ extensions->eglImage = true;
+ extensions->unpackSubimage = true;
+ extensions->packSubimage = true;
+ extensions->vertexArrayObject = true;
+ extensions->noError = true;
+ extensions->lossyETCDecode = true;
+
+ // D3D11 Feature Level 10_0+ uses SV_IsFrontFace in HLSL to emulate gl_FrontFacing.
+ // D3D11 Feature Level 9_3 doesn't support SV_IsFrontFace, and has no equivalent, so can't support gl_FrontFacing.
+ limitations->noFrontFacingSupport = (renderer11DeviceCaps.featureLevel <= D3D_FEATURE_LEVEL_9_3);
+
+ // D3D11 Feature Level 9_3 doesn't support alpha-to-coverage
+ limitations->noSampleAlphaToCoverageSupport = (renderer11DeviceCaps.featureLevel <= D3D_FEATURE_LEVEL_9_3);
+
+ // D3D11 Feature Levels 9_3 and below do not support non-constant loop indexing and require
+ // additional
+ // pre-validation of the shader at compile time to produce a better error message.
+ limitations->shadersRequireIndexedLoopValidation =
+ (renderer11DeviceCaps.featureLevel <= D3D_FEATURE_LEVEL_9_3);
+
+ // D3D11 has no concept of separate masks and refs for front and back faces in the depth stencil
+ // state.
+ limitations->noSeparateStencilRefsAndMasks = true;
+
+ // D3D11 cannot support constant color and alpha blend funcs together
+ limitations->noSimultaneousConstantColorAndAlphaBlendFunc = true;
+
+#ifdef ANGLE_ENABLE_WINDOWS_STORE
+ // Setting a non-zero divisor on attribute zero doesn't work on certain Windows Phone 8-era devices.
+ // We should prevent developers from doing this on ALL Windows Store devices. This will maintain consistency across all Windows devices.
+ // We allow non-zero divisors on attribute zero if the Client Version >= 3, since devices affected by this issue don't support ES3+.
+ limitations->attributeZeroRequiresZeroDivisorInEXT = true;
+#endif
}
-}
+} // namespace d3d11_gl
namespace d3d11
{
+ANGLED3D11DeviceType GetDeviceType(ID3D11Device *device)
+{
+ // Note that this function returns an ANGLED3D11DeviceType rather than a D3D_DRIVER_TYPE value,
+ // since it is difficult to tell Software and Reference devices apart
+
+ IDXGIDevice *dxgiDevice = nullptr;
+ IDXGIAdapter *dxgiAdapter = nullptr;
+#if defined(ANGLE_ENABLE_D3D11_1)
+ IDXGIAdapter2 *dxgiAdapter2 = nullptr;
+#endif
+
+ ANGLED3D11DeviceType retDeviceType = ANGLE_D3D11_DEVICE_TYPE_UNKNOWN;
+
+ HRESULT hr = device->QueryInterface(__uuidof(IDXGIDevice), (void **)&dxgiDevice);
+ if (SUCCEEDED(hr))
+ {
+ hr = dxgiDevice->GetParent(__uuidof(IDXGIAdapter), (void **)&dxgiAdapter);
+ if (SUCCEEDED(hr))
+ {
+ std::wstring adapterString;
+#if defined(ANGLE_ENABLE_D3D11_1)
+ HRESULT adapter2hr =
+ dxgiAdapter->QueryInterface(__uuidof(dxgiAdapter2), (void **)&dxgiAdapter2);
+ if (SUCCEEDED(adapter2hr))
+ {
+ // On D3D_FEATURE_LEVEL_9_*, IDXGIAdapter::GetDesc returns "Software Adapter"
+ // for the description string. Try to use IDXGIAdapter2::GetDesc2 to get the
+ // actual hardware values if possible.
+ DXGI_ADAPTER_DESC2 adapterDesc2;
+ dxgiAdapter2->GetDesc2(&adapterDesc2);
+ adapterString = std::wstring(adapterDesc2.Description);
+ }
+ else
+#endif
+ {
+ DXGI_ADAPTER_DESC adapterDesc;
+ dxgiAdapter->GetDesc(&adapterDesc);
+ adapterString = std::wstring(adapterDesc.Description);
+ }
+
+ // Both Reference and Software adapters will be 'Software Adapter'
+ const bool isSoftwareDevice =
+ (adapterString.find(std::wstring(L"Software Adapter")) != std::string::npos);
+ const bool isNullDevice = (adapterString == L"");
+ const bool isWARPDevice =
+ (adapterString.find(std::wstring(L"Basic Render")) != std::string::npos);
+
+ if (isSoftwareDevice || isNullDevice)
+ {
+ ASSERT(!isWARPDevice);
+ retDeviceType = ANGLE_D3D11_DEVICE_TYPE_SOFTWARE_REF_OR_NULL;
+ }
+ else if (isWARPDevice)
+ {
+ retDeviceType = ANGLE_D3D11_DEVICE_TYPE_WARP;
+ }
+ else
+ {
+ retDeviceType = ANGLE_D3D11_DEVICE_TYPE_HARDWARE;
+ }
+ }
+ }
+
+ SafeRelease(dxgiDevice);
+ SafeRelease(dxgiAdapter);
+#if defined(ANGLE_ENABLE_D3D11_1)
+ SafeRelease(dxgiAdapter2);
+#endif
+
+ return retDeviceType;
+}
+
void MakeValidSize(bool isImage, DXGI_FORMAT format, GLsizei *requestWidth, GLsizei *requestHeight, int *levelOffset)
{
const DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(format);
@@ -1293,11 +1436,16 @@ void MakeValidSize(bool isImage, DXGI_FORMAT format, GLsizei *requestWidth, GLsi
*levelOffset = upsampleCount;
}
-void GenerateInitialTextureData(GLint internalFormat, D3D_FEATURE_LEVEL featureLevel, GLuint width, GLuint height, GLuint depth,
- GLuint mipLevels, std::vector<D3D11_SUBRESOURCE_DATA> *outSubresourceData,
- std::vector< std::vector<BYTE> > *outData)
+void GenerateInitialTextureData(GLint internalFormat,
+ const Renderer11DeviceCaps &renderer11DeviceCaps,
+ GLuint width,
+ GLuint height,
+ GLuint depth,
+ GLuint mipLevels,
+ std::vector<D3D11_SUBRESOURCE_DATA> *outSubresourceData,
+ std::vector<std::vector<BYTE>> *outData)
{
- const d3d11::TextureFormat &d3dFormatInfo = d3d11::GetTextureFormatInfo(internalFormat, featureLevel);
+ const d3d11::TextureFormat &d3dFormatInfo = d3d11::GetTextureFormatInfo(internalFormat, renderer11DeviceCaps);
ASSERT(d3dFormatInfo.dataInitializerFunction != NULL);
const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(d3dFormatInfo.texFormat);
@@ -1323,6 +1471,11 @@ void GenerateInitialTextureData(GLint internalFormat, D3D_FEATURE_LEVEL featureL
}
}
+UINT GetPrimitiveRestartIndex()
+{
+ return std::numeric_limits<UINT>::max();
+}
+
void SetPositionTexCoordVertex(PositionTexCoordVertex* vertex, float x, float y, float u, float v)
{
vertex->x = x;
@@ -1345,27 +1498,94 @@ void SetPositionLayerTexCoord3DVertex(PositionLayerTexCoord3DVertex* vertex, flo
HRESULT SetDebugName(ID3D11DeviceChild *resource, const char *name)
{
#if defined(_DEBUG)
- return resource->SetPrivateData(WKPDID_D3DDebugObjectName, strlen(name), name);
+ UINT existingDataSize = 0;
+ resource->GetPrivateData(WKPDID_D3DDebugObjectName, &existingDataSize, nullptr);
+ // Don't check the HRESULT- if it failed then that probably just means that no private data
+ // exists yet
+
+ if (existingDataSize > 0)
+ {
+ // In some cases, ANGLE will try to apply two names to one object, which causes
+ // a D3D SDK Layers warning. This can occur if, for example, you 'create' two objects
+ // (e.g.Rasterizer States) with identical DESCs on the same device. D3D11 will optimize
+ // these calls and return the same object both times.
+ static const char *multipleNamesUsed = "Multiple names set by ANGLE";
+
+ // Remove the existing name
+ HRESULT hr = resource->SetPrivateData(WKPDID_D3DDebugObjectName, 0, nullptr);
+ if (FAILED(hr))
+ {
+ return hr;
+ }
+
+ // Apply the new name
+ return resource->SetPrivateData(WKPDID_D3DDebugObjectName,
+ static_cast<unsigned int>(strlen(multipleNamesUsed)),
+ multipleNamesUsed);
+ }
+ else
+ {
+ return resource->SetPrivateData(WKPDID_D3DDebugObjectName,
+ static_cast<unsigned int>(strlen(name)), name);
+ }
#else
return S_OK;
#endif
}
-gl::Error GetAttachmentRenderTarget(const gl::FramebufferAttachment *attachment, RenderTarget11 **outRT)
+LazyInputLayout::LazyInputLayout(const D3D11_INPUT_ELEMENT_DESC *inputDesc,
+ size_t inputDescLen,
+ const BYTE *byteCode,
+ size_t byteCodeLen,
+ const char *debugName)
+ : mInputDesc(inputDescLen),
+ mByteCodeLen(byteCodeLen),
+ mByteCode(byteCode),
+ mDebugName(debugName)
+{
+ memcpy(&mInputDesc[0], inputDesc, sizeof(D3D11_INPUT_ELEMENT_DESC) * inputDescLen);
+}
+
+ID3D11InputLayout *LazyInputLayout::resolve(ID3D11Device *device)
+{
+ checkAssociatedDevice(device);
+
+ if (mResource == nullptr)
+ {
+ HRESULT result =
+ device->CreateInputLayout(&mInputDesc[0], static_cast<UINT>(mInputDesc.size()),
+ mByteCode, mByteCodeLen, &mResource);
+ ASSERT(SUCCEEDED(result));
+ UNUSED_ASSERTION_VARIABLE(result);
+ d3d11::SetDebugName(mResource, mDebugName);
+ }
+
+ return mResource;
+}
+
+LazyBlendState::LazyBlendState(const D3D11_BLEND_DESC &desc, const char *debugName)
+ : mDesc(desc), mDebugName(debugName)
+{
+}
+
+ID3D11BlendState *LazyBlendState::resolve(ID3D11Device *device)
{
- RenderTargetD3D *renderTarget = NULL;
- gl::Error error = rx::GetAttachmentRenderTarget(attachment, &renderTarget);
- if (error.isError())
+ checkAssociatedDevice(device);
+
+ if (mResource == nullptr)
{
- return error;
+ HRESULT result = device->CreateBlendState(&mDesc, &mResource);
+ ASSERT(SUCCEEDED(result));
+ UNUSED_ASSERTION_VARIABLE(result);
+ d3d11::SetDebugName(mResource, mDebugName);
}
- *outRT = RenderTarget11::makeRenderTarget11(renderTarget);
- return gl::Error(GL_NO_ERROR);
+
+ return mResource;
}
-Workarounds GenerateWorkarounds(D3D_FEATURE_LEVEL featureLevel)
+WorkaroundsD3D GenerateWorkarounds(D3D_FEATURE_LEVEL featureLevel)
{
- Workarounds workarounds;
+ WorkaroundsD3D workarounds;
workarounds.mrtPerfWorkaround = true;
workarounds.setDataFasterThanImageUpload = true;
workarounds.zeroMaxLodWorkaround = (featureLevel <= D3D_FEATURE_LEVEL_9_3);
@@ -1373,6 +1593,188 @@ Workarounds GenerateWorkarounds(D3D_FEATURE_LEVEL featureLevel)
return workarounds;
}
+} // namespace d3d11
+
+TextureHelper11::TextureHelper11()
+ : mTextureType(GL_NONE),
+ mFormat(DXGI_FORMAT_UNKNOWN),
+ mSampleCount(0),
+ mTexture2D(nullptr),
+ mTexture3D(nullptr)
+{
+}
+
+TextureHelper11::TextureHelper11(TextureHelper11 &&toCopy)
+ : mTextureType(toCopy.mTextureType),
+ mExtents(toCopy.mExtents),
+ mFormat(toCopy.mFormat),
+ mSampleCount(toCopy.mSampleCount),
+ mTexture2D(toCopy.mTexture2D),
+ mTexture3D(toCopy.mTexture3D)
+{
+ toCopy.reset();
+}
+
+// static
+TextureHelper11 TextureHelper11::MakeAndReference(ID3D11Resource *genericResource)
+{
+ TextureHelper11 newHelper;
+ newHelper.mTexture2D = d3d11::DynamicCastComObject<ID3D11Texture2D>(genericResource);
+ newHelper.mTexture3D = d3d11::DynamicCastComObject<ID3D11Texture3D>(genericResource);
+ newHelper.mTextureType = newHelper.mTexture2D ? GL_TEXTURE_2D : GL_TEXTURE_3D;
+ newHelper.initDesc();
+ return newHelper;
+}
+
+// static
+TextureHelper11 TextureHelper11::MakeAndPossess2D(ID3D11Texture2D *texToOwn)
+{
+ TextureHelper11 newHelper;
+ newHelper.mTexture2D = texToOwn;
+ newHelper.mTextureType = GL_TEXTURE_2D;
+ newHelper.initDesc();
+ return newHelper;
+}
+
+// static
+TextureHelper11 TextureHelper11::MakeAndPossess3D(ID3D11Texture3D *texToOwn)
+{
+ TextureHelper11 newHelper;
+ newHelper.mTexture3D = texToOwn;
+ newHelper.mTextureType = GL_TEXTURE_3D;
+ newHelper.initDesc();
+ return newHelper;
+}
+
+void TextureHelper11::initDesc()
+{
+ if (mTextureType == GL_TEXTURE_2D)
+ {
+ ASSERT(!mTexture3D);
+ D3D11_TEXTURE2D_DESC desc2D;
+ mTexture2D->GetDesc(&desc2D);
+
+ mExtents.width = static_cast<int>(desc2D.Width);
+ mExtents.height = static_cast<int>(desc2D.Height);
+ mExtents.depth = 1;
+ mFormat = desc2D.Format;
+ mSampleCount = desc2D.SampleDesc.Count;
+ }
+ else
+ {
+ ASSERT(mTexture3D && mTextureType == GL_TEXTURE_3D);
+ D3D11_TEXTURE3D_DESC desc3D;
+ mTexture3D->GetDesc(&desc3D);
+
+ mExtents.width = static_cast<int>(desc3D.Width);
+ mExtents.height = static_cast<int>(desc3D.Height);
+ mExtents.depth = static_cast<int>(desc3D.Depth);
+ mFormat = desc3D.Format;
+ mSampleCount = 1;
+ }
+}
+
+TextureHelper11::~TextureHelper11()
+{
+ SafeRelease(mTexture2D);
+ SafeRelease(mTexture3D);
+}
+
+ID3D11Resource *TextureHelper11::getResource() const
+{
+ return mTexture2D ? static_cast<ID3D11Resource *>(mTexture2D)
+ : static_cast<ID3D11Resource *>(mTexture3D);
+}
+
+TextureHelper11 &TextureHelper11::operator=(TextureHelper11 &&texture)
+{
+ SafeRelease(mTexture2D);
+ SafeRelease(mTexture3D);
+
+ mTextureType = texture.mTextureType;
+ mExtents = texture.mExtents;
+ mFormat = texture.mFormat;
+ mSampleCount = texture.mSampleCount;
+ mTexture2D = texture.mTexture2D;
+ mTexture3D = texture.mTexture3D;
+ texture.reset();
+ return *this;
+}
+
+void TextureHelper11::reset()
+{
+ mTextureType = GL_NONE;
+ mExtents = gl::Extents();
+ mFormat = DXGI_FORMAT_UNKNOWN;
+ mSampleCount = 0;
+ mTexture2D = nullptr;
+ mTexture3D = nullptr;
+}
+
+gl::ErrorOrResult<TextureHelper11> CreateStagingTexture(GLenum textureType,
+ DXGI_FORMAT dxgiFormat,
+ const gl::Extents &size,
+ ID3D11Device *device)
+{
+ if (textureType == GL_TEXTURE_2D)
+ {
+ D3D11_TEXTURE2D_DESC stagingDesc;
+ stagingDesc.Width = size.width;
+ stagingDesc.Height = size.height;
+ stagingDesc.MipLevels = 1;
+ stagingDesc.ArraySize = 1;
+ stagingDesc.Format = dxgiFormat;
+ stagingDesc.SampleDesc.Count = 1;
+ stagingDesc.SampleDesc.Quality = 0;
+ stagingDesc.Usage = D3D11_USAGE_STAGING;
+ stagingDesc.BindFlags = 0;
+ stagingDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
+ stagingDesc.MiscFlags = 0;
+
+ ID3D11Texture2D *stagingTex = nullptr;
+ HRESULT result = device->CreateTexture2D(&stagingDesc, nullptr, &stagingTex);
+ if (FAILED(result))
+ {
+ return gl::Error(GL_OUT_OF_MEMORY, "CreateStagingTextureFor failed, HRESULT: 0x%X.",
+ result);
+ }
+
+ return TextureHelper11::MakeAndPossess2D(stagingTex);
+ }
+ ASSERT(textureType == GL_TEXTURE_3D);
+
+ D3D11_TEXTURE3D_DESC stagingDesc;
+ stagingDesc.Width = size.width;
+ stagingDesc.Height = size.height;
+ stagingDesc.Depth = 1;
+ stagingDesc.MipLevels = 1;
+ stagingDesc.Format = dxgiFormat;
+ stagingDesc.Usage = D3D11_USAGE_STAGING;
+ stagingDesc.BindFlags = 0;
+ stagingDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
+ stagingDesc.MiscFlags = 0;
+
+ ID3D11Texture3D *stagingTex = nullptr;
+ HRESULT result = device->CreateTexture3D(&stagingDesc, nullptr, &stagingTex);
+ if (FAILED(result))
+ {
+ return gl::Error(GL_OUT_OF_MEMORY, "CreateStagingTextureFor failed, HRESULT: 0x%X.",
+ result);
+ }
+
+ return TextureHelper11::MakeAndPossess3D(stagingTex);
}
+bool UsePresentPathFast(const Renderer11 *renderer,
+ const gl::FramebufferAttachment *framebufferAttachment)
+{
+ if (framebufferAttachment == nullptr)
+ {
+ return false;
+ }
+
+ return (framebufferAttachment->type() == GL_FRAMEBUFFER_DEFAULT &&
+ renderer->presentPathFastEnabled());
}
+
+} // namespace rx
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.h
index 207e6b5404..4925a2d227 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.h
@@ -10,11 +10,13 @@
#ifndef LIBANGLE_RENDERER_D3D_D3D11_RENDERER11_UTILS_H_
#define LIBANGLE_RENDERER_D3D_D3D11_RENDERER11_UTILS_H_
+#include <array>
+#include <vector>
+
#include "libANGLE/angletypes.h"
#include "libANGLE/Caps.h"
#include "libANGLE/Error.h"
-
-#include <vector>
+#include "libANGLE/renderer/d3d/RendererD3D.h"
namespace gl
{
@@ -23,8 +25,12 @@ class FramebufferAttachment;
namespace rx
{
+class Renderer11;
class RenderTarget11;
-struct Workarounds;
+struct WorkaroundsD3D;
+struct Renderer11DeviceCaps;
+
+using RenderTargetArray = std::array<ID3D11RenderTargetView *, gl::IMPLEMENTATION_MAX_DRAW_BUFFERS>;
namespace gl_d3d11
{
@@ -45,24 +51,46 @@ D3D11_TEXTURE_ADDRESS_MODE ConvertTextureWrap(GLenum wrap);
D3D11_QUERY ConvertQueryType(GLenum queryType);
-}
+} // namespace gl_d3d11
namespace d3d11_gl
{
+unsigned int GetReservedVertexUniformVectors(D3D_FEATURE_LEVEL featureLevel);
+
+unsigned int GetReservedFragmentUniformVectors(D3D_FEATURE_LEVEL featureLevel);
+
GLint GetMaximumClientVersion(D3D_FEATURE_LEVEL featureLevel);
-void GenerateCaps(ID3D11Device *device, ID3D11DeviceContext *deviceContext, gl::Caps *caps, gl::TextureCapsMap *textureCapsMap, gl::Extensions *extensions);
+void GenerateCaps(ID3D11Device *device, ID3D11DeviceContext *deviceContext, const Renderer11DeviceCaps &renderer11DeviceCaps, gl::Caps *caps,
+ gl::TextureCapsMap *textureCapsMap, gl::Extensions *extensions, gl::Limitations *limitations);
-}
+} // namespace d3d11_gl
namespace d3d11
{
+enum ANGLED3D11DeviceType
+{
+ ANGLE_D3D11_DEVICE_TYPE_UNKNOWN,
+ ANGLE_D3D11_DEVICE_TYPE_HARDWARE,
+ ANGLE_D3D11_DEVICE_TYPE_SOFTWARE_REF_OR_NULL,
+ ANGLE_D3D11_DEVICE_TYPE_WARP,
+};
+
+ANGLED3D11DeviceType GetDeviceType(ID3D11Device *device);
+
void MakeValidSize(bool isImage, DXGI_FORMAT format, GLsizei *requestWidth, GLsizei *requestHeight, int *levelOffset);
-void GenerateInitialTextureData(GLint internalFormat, D3D_FEATURE_LEVEL featureLevel, GLuint width, GLuint height, GLuint depth,
- GLuint mipLevels, std::vector<D3D11_SUBRESOURCE_DATA> *outSubresourceData,
- std::vector< std::vector<BYTE> > *outData);
+void GenerateInitialTextureData(GLint internalFormat,
+ const Renderer11DeviceCaps &renderer11DeviceCaps,
+ GLuint width,
+ GLuint height,
+ GLuint depth,
+ GLuint mipLevels,
+ std::vector<D3D11_SUBRESOURCE_DATA> *outSubresourceData,
+ std::vector<std::vector<BYTE>> *outData);
+
+UINT GetPrimitiveRestartIndex();
struct PositionTexCoordVertex
{
@@ -133,58 +161,230 @@ inline bool isDeviceLostError(HRESULT errorCode)
}
}
-template <unsigned int N>
-inline ID3D11VertexShader *CompileVS(ID3D11Device *device, const BYTE (&byteCode)[N], const char *name)
+inline ID3D11VertexShader *CompileVS(ID3D11Device *device, const BYTE *byteCode, size_t N, const char *name)
{
- ID3D11VertexShader *vs = NULL;
- HRESULT result = device->CreateVertexShader(byteCode, N, NULL, &vs);
- UNUSED_ASSERTION_VARIABLE(result);
+ ID3D11VertexShader *vs = nullptr;
+ HRESULT result = device->CreateVertexShader(byteCode, N, nullptr, &vs);
ASSERT(SUCCEEDED(result));
- SetDebugName(vs, name);
- return vs;
+ if (SUCCEEDED(result))
+ {
+ SetDebugName(vs, name);
+ return vs;
+ }
+ return nullptr;
}
template <unsigned int N>
-inline ID3D11GeometryShader *CompileGS(ID3D11Device *device, const BYTE (&byteCode)[N], const char *name)
+ID3D11VertexShader *CompileVS(ID3D11Device *device, const BYTE (&byteCode)[N], const char *name)
+{
+ return CompileVS(device, byteCode, N, name);
+}
+
+inline ID3D11GeometryShader *CompileGS(ID3D11Device *device, const BYTE *byteCode, size_t N, const char *name)
{
- ID3D11GeometryShader *gs = NULL;
- HRESULT result = device->CreateGeometryShader(byteCode, N, NULL, &gs);
- UNUSED_ASSERTION_VARIABLE(result);
+ ID3D11GeometryShader *gs = nullptr;
+ HRESULT result = device->CreateGeometryShader(byteCode, N, nullptr, &gs);
ASSERT(SUCCEEDED(result));
- SetDebugName(gs, name);
- return gs;
+ if (SUCCEEDED(result))
+ {
+ SetDebugName(gs, name);
+ return gs;
+ }
+ return nullptr;
}
template <unsigned int N>
-inline ID3D11PixelShader *CompilePS(ID3D11Device *device, const BYTE (&byteCode)[N], const char *name)
+ID3D11GeometryShader *CompileGS(ID3D11Device *device, const BYTE (&byteCode)[N], const char *name)
+{
+ return CompileGS(device, byteCode, N, name);
+}
+
+inline ID3D11PixelShader *CompilePS(ID3D11Device *device, const BYTE *byteCode, size_t N, const char *name)
{
- ID3D11PixelShader *ps = NULL;
- HRESULT result = device->CreatePixelShader(byteCode, N, NULL, &ps);
- UNUSED_ASSERTION_VARIABLE(result);
+ ID3D11PixelShader *ps = nullptr;
+ HRESULT result = device->CreatePixelShader(byteCode, N, nullptr, &ps);
ASSERT(SUCCEEDED(result));
- SetDebugName(ps, name);
- return ps;
+ if (SUCCEEDED(result))
+ {
+ SetDebugName(ps, name);
+ return ps;
+ }
+ return nullptr;
}
-// Copy data to small D3D11 buffers, such as for small constant buffers, which use one struct to
-// represent an entire buffer.
-template <class T>
-inline void SetBufferData(ID3D11DeviceContext *context, ID3D11Buffer *constantBuffer, const T &value)
+template <unsigned int N>
+ID3D11PixelShader *CompilePS(ID3D11Device *device, const BYTE (&byteCode)[N], const char *name)
+{
+ return CompilePS(device, byteCode, N, name);
+}
+
+template <typename ResourceType>
+class LazyResource : public angle::NonCopyable
{
- D3D11_MAPPED_SUBRESOURCE mappedResource;
- context->Map(constantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
+ public:
+ LazyResource() : mResource(nullptr), mAssociatedDevice(nullptr) {}
+ virtual ~LazyResource() { release(); }
+
+ virtual ResourceType *resolve(ID3D11Device *device) = 0;
+ void release() { SafeRelease(mResource); }
- memcpy(mappedResource.pData, &value, sizeof(T));
+ protected:
+ void checkAssociatedDevice(ID3D11Device *device);
- context->Unmap(constantBuffer, 0);
+ ResourceType *mResource;
+ ID3D11Device *mAssociatedDevice;
+};
+
+template <typename ResourceType>
+void LazyResource<ResourceType>::checkAssociatedDevice(ID3D11Device *device)
+{
+ ASSERT(mAssociatedDevice == nullptr || device == mAssociatedDevice);
+ mAssociatedDevice = device;
}
-gl::Error GetAttachmentRenderTarget(const gl::FramebufferAttachment *attachment, RenderTarget11 **outRT);
+template <typename D3D11ShaderType>
+class LazyShader final : public LazyResource<D3D11ShaderType>
+{
+ public:
+ // All parameters must be constexpr. Not supported in VS2013.
+ LazyShader(const BYTE *byteCode,
+ size_t byteCodeSize,
+ const char *name)
+ : mByteCode(byteCode),
+ mByteCodeSize(byteCodeSize),
+ mName(name)
+ {
+ }
-Workarounds GenerateWorkarounds(D3D_FEATURE_LEVEL featureLevel);
+ D3D11ShaderType *resolve(ID3D11Device *device) override;
+ private:
+ const BYTE *mByteCode;
+ size_t mByteCodeSize;
+ const char *mName;
+};
+
+template <>
+inline ID3D11VertexShader *LazyShader<ID3D11VertexShader>::resolve(ID3D11Device *device)
+{
+ checkAssociatedDevice(device);
+ if (mResource == nullptr)
+ {
+ mResource = CompileVS(device, mByteCode, mByteCodeSize, mName);
+ }
+ return mResource;
}
+template <>
+inline ID3D11GeometryShader *LazyShader<ID3D11GeometryShader>::resolve(ID3D11Device *device)
+{
+ checkAssociatedDevice(device);
+ if (mResource == nullptr)
+ {
+ mResource = CompileGS(device, mByteCode, mByteCodeSize, mName);
+ }
+ return mResource;
}
+template <>
+inline ID3D11PixelShader *LazyShader<ID3D11PixelShader>::resolve(ID3D11Device *device)
+{
+ checkAssociatedDevice(device);
+ if (mResource == nullptr)
+ {
+ mResource = CompilePS(device, mByteCode, mByteCodeSize, mName);
+ }
+ return mResource;
+}
+
+class LazyInputLayout final : public LazyResource<ID3D11InputLayout>
+{
+ public:
+ LazyInputLayout(const D3D11_INPUT_ELEMENT_DESC *inputDesc,
+ size_t inputDescLen,
+ const BYTE *byteCode,
+ size_t byteCodeLen,
+ const char *debugName);
+
+ ID3D11InputLayout *resolve(ID3D11Device *device) override;
+
+ private:
+ std::vector<D3D11_INPUT_ELEMENT_DESC> mInputDesc;
+ size_t mByteCodeLen;
+ const BYTE *mByteCode;
+ const char *mDebugName;
+};
+
+class LazyBlendState final : public LazyResource<ID3D11BlendState>
+{
+ public:
+ LazyBlendState(const D3D11_BLEND_DESC &desc, const char *debugName);
+
+ ID3D11BlendState *resolve(ID3D11Device *device) override;
+
+ private:
+ D3D11_BLEND_DESC mDesc;
+ const char *mDebugName;
+};
+
+// Copy data to small D3D11 buffers, such as for small constant buffers, which use one struct to
+// represent an entire buffer.
+template <class T>
+void SetBufferData(ID3D11DeviceContext *context, ID3D11Buffer *constantBuffer, const T &value)
+{
+ D3D11_MAPPED_SUBRESOURCE mappedResource = {};
+ HRESULT result = context->Map(constantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
+ ASSERT(SUCCEEDED(result));
+ if (SUCCEEDED(result))
+ {
+ memcpy(mappedResource.pData, &value, sizeof(T));
+ context->Unmap(constantBuffer, 0);
+ }
+}
+
+WorkaroundsD3D GenerateWorkarounds(D3D_FEATURE_LEVEL featureLevel);
+} // namespace d3d11
+
+// A helper class which wraps a 2D or 3D texture.
+class TextureHelper11 : angle::NonCopyable
+{
+ public:
+ TextureHelper11();
+ TextureHelper11(TextureHelper11 &&toCopy);
+ ~TextureHelper11();
+ TextureHelper11 &operator=(TextureHelper11 &&texture);
+
+ static TextureHelper11 MakeAndReference(ID3D11Resource *genericResource);
+ static TextureHelper11 MakeAndPossess2D(ID3D11Texture2D *texToOwn);
+ static TextureHelper11 MakeAndPossess3D(ID3D11Texture3D *texToOwn);
+
+ GLenum getTextureType() const { return mTextureType; }
+ gl::Extents getExtents() const { return mExtents; }
+ DXGI_FORMAT getFormat() const { return mFormat; }
+ int getSampleCount() const { return mSampleCount; }
+ ID3D11Texture2D *getTexture2D() const { return mTexture2D; }
+ ID3D11Texture3D *getTexture3D() const { return mTexture3D; }
+ ID3D11Resource *getResource() const;
+
+ private:
+ void reset();
+ void initDesc();
+
+ GLenum mTextureType;
+ gl::Extents mExtents;
+ DXGI_FORMAT mFormat;
+ int mSampleCount;
+ ID3D11Texture2D *mTexture2D;
+ ID3D11Texture3D *mTexture3D;
+};
+
+gl::ErrorOrResult<TextureHelper11> CreateStagingTexture(GLenum textureType,
+ DXGI_FORMAT dxgiFormat,
+ const gl::Extents &size,
+ ID3D11Device *device);
+
+bool UsePresentPathFast(const Renderer11 *renderer, const gl::FramebufferAttachment *colorbuffer);
+
+} // namespace rx
+
#endif // LIBANGLE_RENDERER_D3D_D3D11_RENDERER11_UTILS_H_
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/swizzle_format_data.json b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/swizzle_format_data.json
new file mode 100644
index 0000000000..3e9e6877d9
--- /dev/null
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/swizzle_format_data.json
@@ -0,0 +1,77 @@
+{
+ "GL_UNSIGNED_NORMALIZED": {
+ "8": {
+ "texFormat": "DXGI_FORMAT_R8G8B8A8_UNORM",
+ "srvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM",
+ "rtvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM"
+ },
+ "16": {
+ "texFormat": "DXGI_FORMAT_R16G16B16A16_UNORM",
+ "srvFormat": "DXGI_FORMAT_R16G16B16A16_UNORM",
+ "rtvFormat": "DXGI_FORMAT_R16G16B16A16_UNORM"
+ },
+ "24": {
+ "texFormat": "DXGI_FORMAT_R32G32B32A32_FLOAT",
+ "srvFormat": "DXGI_FORMAT_R32G32B32A32_FLOAT",
+ "rtvFormat": "DXGI_FORMAT_R32G32B32A32_FLOAT"
+ },
+ "32": {
+ "texFormat": "DXGI_FORMAT_R32G32B32A32_FLOAT",
+ "srvFormat": "DXGI_FORMAT_R32G32B32A32_FLOAT",
+ "rtvFormat": "DXGI_FORMAT_R32G32B32A32_FLOAT"
+ }
+ },
+ "GL_SIGNED_NORMALIZED": {
+ "8": {
+ "texFormat": "DXGI_FORMAT_R8G8B8A8_SNORM",
+ "srvFormat": "DXGI_FORMAT_R8G8B8A8_SNORM",
+ "rtvFormat": "DXGI_FORMAT_R8G8B8A8_SNORM"
+ }
+ },
+ "GL_FLOAT": {
+ "16": {
+ "texFormat": "DXGI_FORMAT_R16G16B16A16_FLOAT",
+ "srvFormat": "DXGI_FORMAT_R16G16B16A16_FLOAT",
+ "rtvFormat": "DXGI_FORMAT_R16G16B16A16_FLOAT"
+ },
+ "32": {
+ "texFormat": "DXGI_FORMAT_R32G32B32A32_FLOAT",
+ "srvFormat": "DXGI_FORMAT_R32G32B32A32_FLOAT",
+ "rtvFormat": "DXGI_FORMAT_R32G32B32A32_FLOAT"
+ }
+ },
+ "GL_UNSIGNED_INT": {
+ "8": {
+ "texFormat": "DXGI_FORMAT_R8G8B8A8_UINT",
+ "srvFormat": "DXGI_FORMAT_R8G8B8A8_UINT",
+ "rtvFormat": "DXGI_FORMAT_R8G8B8A8_UINT"
+ },
+ "16": {
+ "texFormat": "DXGI_FORMAT_R16G16B16A16_UINT",
+ "srvFormat": "DXGI_FORMAT_R16G16B16A16_UINT",
+ "rtvFormat": "DXGI_FORMAT_R16G16B16A16_UINT"
+ },
+ "32": {
+ "texFormat": "DXGI_FORMAT_R32G32B32A32_UINT",
+ "srvFormat": "DXGI_FORMAT_R32G32B32A32_UINT",
+ "rtvFormat": "DXGI_FORMAT_R32G32B32A32_UINT"
+ }
+ },
+ "GL_INT": {
+ "8": {
+ "texFormat": "DXGI_FORMAT_R8G8B8A8_SINT",
+ "srvFormat": "DXGI_FORMAT_R8G8B8A8_SINT",
+ "rtvFormat": "DXGI_FORMAT_R8G8B8A8_SINT"
+ },
+ "16": {
+ "texFormat": "DXGI_FORMAT_R16G16B16A16_SINT",
+ "srvFormat": "DXGI_FORMAT_R16G16B16A16_SINT",
+ "rtvFormat": "DXGI_FORMAT_R16G16B16A16_SINT"
+ },
+ "32": {
+ "texFormat": "DXGI_FORMAT_R32G32B32A32_SINT",
+ "srvFormat": "DXGI_FORMAT_R32G32B32A32_SINT",
+ "rtvFormat": "DXGI_FORMAT_R32G32B32A32_SINT"
+ }
+ }
+} \ No newline at end of file
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/swizzle_format_info.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/swizzle_format_info.h
new file mode 100644
index 0000000000..df9a30ff50
--- /dev/null
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/swizzle_format_info.h
@@ -0,0 +1,51 @@
+//
+// 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.
+//
+// swizzle_format_info:
+// Provides information for swizzle format and a map from type->formatinfo
+//
+
+#ifndef LIBANGLE_RENDERER_D3D_D3D11_SWIZZLEFORMATINFO_H_
+#define LIBANGLE_RENDERER_D3D_D3D11_SWIZZLEFORMATINFO_H_
+
+#include <GLES2/gl2.h>
+#include <map>
+
+#include "common/platform.h"
+
+namespace rx
+{
+
+namespace d3d11
+{
+
+struct SwizzleSizeType
+{
+ size_t maxComponentSize;
+ GLenum componentType;
+
+ SwizzleSizeType();
+ SwizzleSizeType(size_t maxComponentSize, GLenum componentType);
+
+ bool operator<(const SwizzleSizeType &other) const;
+};
+
+struct SwizzleFormatInfo
+{
+ DXGI_FORMAT mTexFormat;
+ DXGI_FORMAT mSRVFormat;
+ DXGI_FORMAT mRTVFormat;
+
+ SwizzleFormatInfo();
+ SwizzleFormatInfo(DXGI_FORMAT texFormat, DXGI_FORMAT srvFormat, DXGI_FORMAT rtvFormat);
+};
+
+const SwizzleFormatInfo &GetSwizzleFormatInfo(GLuint maxBits, GLenum componentType);
+
+} // namespace d3d11
+
+} // namespace rx
+
+#endif // LIBANGLE_RENDERER_D3D_D3D11_SWIZZLEFORMATINFO_H_
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/swizzle_format_info_autogen.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/swizzle_format_info_autogen.cpp
new file mode 100644
index 0000000000..84d6fada97
--- /dev/null
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/swizzle_format_info_autogen.cpp
@@ -0,0 +1,203 @@
+// GENERATED FILE - DO NOT EDIT
+// Generated by gen_swizzle_format_table.py using data from swizzle_format_data.json
+//
+// 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.
+//
+// swizzle_format_info:
+// Provides information for swizzle format and a map from type->formatinfo
+//
+
+#include "libANGLE/renderer/d3d/d3d11/swizzle_format_info.h"
+
+#include <GLES3/gl3.h>
+
+namespace rx
+{
+
+namespace d3d11
+{
+
+SwizzleSizeType::SwizzleSizeType() : maxComponentSize(0), componentType(GL_NONE)
+{
+}
+
+SwizzleSizeType::SwizzleSizeType(size_t maxComponentSize, GLenum componentType)
+ : maxComponentSize(maxComponentSize), componentType(componentType)
+{
+}
+
+bool SwizzleSizeType::operator<(const SwizzleSizeType &other) const
+{
+ return (maxComponentSize != other.maxComponentSize)
+ ? (maxComponentSize < other.maxComponentSize)
+ : (componentType < other.componentType);
+}
+
+SwizzleFormatInfo::SwizzleFormatInfo()
+ : mTexFormat(DXGI_FORMAT_UNKNOWN),
+ mSRVFormat(DXGI_FORMAT_UNKNOWN),
+ mRTVFormat(DXGI_FORMAT_UNKNOWN)
+{
+}
+
+SwizzleFormatInfo::SwizzleFormatInfo(DXGI_FORMAT texFormat,
+ DXGI_FORMAT srvFormat,
+ DXGI_FORMAT rtvFormat)
+ : mTexFormat(texFormat), mSRVFormat(srvFormat), mRTVFormat(rtvFormat)
+{
+}
+
+const SwizzleFormatInfo &GetSwizzleFormatInfo(GLuint maxBits, GLenum componentType)
+{
+ // clang-format off
+ switch (componentType)
+ {
+ case GL_FLOAT:
+ {
+ switch (maxBits)
+ {
+ case 16:
+ {
+ static const SwizzleFormatInfo formatInfo(DXGI_FORMAT_R16G16B16A16_FLOAT,
+ DXGI_FORMAT_R16G16B16A16_FLOAT,
+ DXGI_FORMAT_R16G16B16A16_FLOAT);
+ return formatInfo;
+ }
+ case 32:
+ {
+ static const SwizzleFormatInfo formatInfo(DXGI_FORMAT_R32G32B32A32_FLOAT,
+ DXGI_FORMAT_R32G32B32A32_FLOAT,
+ DXGI_FORMAT_R32G32B32A32_FLOAT);
+ return formatInfo;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_INT:
+ {
+ switch (maxBits)
+ {
+ case 16:
+ {
+ static const SwizzleFormatInfo formatInfo(DXGI_FORMAT_R16G16B16A16_SINT,
+ DXGI_FORMAT_R16G16B16A16_SINT,
+ DXGI_FORMAT_R16G16B16A16_SINT);
+ return formatInfo;
+ }
+ case 32:
+ {
+ static const SwizzleFormatInfo formatInfo(DXGI_FORMAT_R32G32B32A32_SINT,
+ DXGI_FORMAT_R32G32B32A32_SINT,
+ DXGI_FORMAT_R32G32B32A32_SINT);
+ return formatInfo;
+ }
+ case 8:
+ {
+ static const SwizzleFormatInfo formatInfo(DXGI_FORMAT_R8G8B8A8_SINT,
+ DXGI_FORMAT_R8G8B8A8_SINT,
+ DXGI_FORMAT_R8G8B8A8_SINT);
+ return formatInfo;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_SIGNED_NORMALIZED:
+ {
+ switch (maxBits)
+ {
+ case 8:
+ {
+ static const SwizzleFormatInfo formatInfo(DXGI_FORMAT_R8G8B8A8_SNORM,
+ DXGI_FORMAT_R8G8B8A8_SNORM,
+ DXGI_FORMAT_R8G8B8A8_SNORM);
+ return formatInfo;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_UNSIGNED_INT:
+ {
+ switch (maxBits)
+ {
+ case 16:
+ {
+ static const SwizzleFormatInfo formatInfo(DXGI_FORMAT_R16G16B16A16_UINT,
+ DXGI_FORMAT_R16G16B16A16_UINT,
+ DXGI_FORMAT_R16G16B16A16_UINT);
+ return formatInfo;
+ }
+ case 32:
+ {
+ static const SwizzleFormatInfo formatInfo(DXGI_FORMAT_R32G32B32A32_UINT,
+ DXGI_FORMAT_R32G32B32A32_UINT,
+ DXGI_FORMAT_R32G32B32A32_UINT);
+ return formatInfo;
+ }
+ case 8:
+ {
+ static const SwizzleFormatInfo formatInfo(DXGI_FORMAT_R8G8B8A8_UINT,
+ DXGI_FORMAT_R8G8B8A8_UINT,
+ DXGI_FORMAT_R8G8B8A8_UINT);
+ return formatInfo;
+ }
+ default:
+ break;
+ }
+ }
+ case GL_UNSIGNED_NORMALIZED:
+ {
+ switch (maxBits)
+ {
+ case 16:
+ {
+ static const SwizzleFormatInfo formatInfo(DXGI_FORMAT_R16G16B16A16_UNORM,
+ DXGI_FORMAT_R16G16B16A16_UNORM,
+ DXGI_FORMAT_R16G16B16A16_UNORM);
+ return formatInfo;
+ }
+ case 24:
+ {
+ static const SwizzleFormatInfo formatInfo(DXGI_FORMAT_R32G32B32A32_FLOAT,
+ DXGI_FORMAT_R32G32B32A32_FLOAT,
+ DXGI_FORMAT_R32G32B32A32_FLOAT);
+ return formatInfo;
+ }
+ case 32:
+ {
+ static const SwizzleFormatInfo formatInfo(DXGI_FORMAT_R32G32B32A32_FLOAT,
+ DXGI_FORMAT_R32G32B32A32_FLOAT,
+ DXGI_FORMAT_R32G32B32A32_FLOAT);
+ return formatInfo;
+ }
+ case 8:
+ {
+ static const SwizzleFormatInfo formatInfo(DXGI_FORMAT_R8G8B8A8_UNORM,
+ DXGI_FORMAT_R8G8B8A8_UNORM,
+ DXGI_FORMAT_R8G8B8A8_UNORM);
+ return formatInfo;
+ }
+ default:
+ break;
+ }
+ }
+
+ default:
+ {
+ static const SwizzleFormatInfo defaultInfo(DXGI_FORMAT_UNKNOWN,
+ DXGI_FORMAT_UNKNOWN,
+ DXGI_FORMAT_UNKNOWN);
+ return defaultInfo;
+ }
+ }
+ // clang-format on
+
+} // GetSwizzleFormatInfo
+
+} // namespace d3d11
+
+} // namespace rx
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/texture_format_data.json b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/texture_format_data.json
new file mode 100644
index 0000000000..87d303437f
--- /dev/null
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/texture_format_data.json
@@ -0,0 +1,692 @@
+{
+ "GL_ALPHA": [
+ {
+ "texFormat": "DXGI_FORMAT_A8_UNORM",
+ "srvFormat": "DXGI_FORMAT_A8_UNORM",
+ "rtvFormat": "DXGI_FORMAT_A8_UNORM",
+ "requirementsFcn": "OnlyFL10Plus"
+ },
+ {
+ "texFormat": "DXGI_FORMAT_R8G8B8A8_UNORM",
+ "srvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM",
+ "rtvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM",
+ "requirementsFcn": "OnlyFL9_3"
+ }
+ ],
+ "GL_ALPHA16F_EXT": [
+ {
+ "texFormat": "DXGI_FORMAT_R16G16B16A16_FLOAT",
+ "srvFormat": "DXGI_FORMAT_R16G16B16A16_FLOAT",
+ "rtvFormat": "DXGI_FORMAT_R16G16B16A16_FLOAT"
+ }
+ ],
+ "GL_ALPHA32F_EXT": [
+ {
+ "texFormat": "DXGI_FORMAT_R32G32B32A32_FLOAT",
+ "srvFormat": "DXGI_FORMAT_R32G32B32A32_FLOAT",
+ "rtvFormat": "DXGI_FORMAT_R32G32B32A32_FLOAT"
+ }
+ ],
+ "GL_ALPHA8_EXT": [
+ {
+ "texFormat": "DXGI_FORMAT_A8_UNORM",
+ "srvFormat": "DXGI_FORMAT_A8_UNORM",
+ "rtvFormat": "DXGI_FORMAT_A8_UNORM",
+ "requirementsFcn": "OnlyFL10Plus"
+ },
+ {
+ "texFormat": "DXGI_FORMAT_R8G8B8A8_UNORM",
+ "srvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM",
+ "rtvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM",
+ "requirementsFcn": "OnlyFL9_3"
+ }
+ ],
+ "GL_BGR5_A1_ANGLEX": [
+ {
+ "texFormat": "DXGI_FORMAT_B8G8R8A8_UNORM",
+ "srvFormat": "DXGI_FORMAT_B8G8R8A8_UNORM",
+ "rtvFormat": "DXGI_FORMAT_B8G8R8A8_UNORM"
+ }
+ ],
+ "GL_BGRA4_ANGLEX": [
+ {
+ "texFormat": "DXGI_FORMAT_B8G8R8A8_UNORM",
+ "srvFormat": "DXGI_FORMAT_B8G8R8A8_UNORM",
+ "rtvFormat": "DXGI_FORMAT_B8G8R8A8_UNORM"
+ }
+ ],
+ "GL_BGRA8_EXT": [
+ {
+ "texFormat": "DXGI_FORMAT_B8G8R8A8_UNORM",
+ "srvFormat": "DXGI_FORMAT_B8G8R8A8_UNORM",
+ "rtvFormat": "DXGI_FORMAT_B8G8R8A8_UNORM"
+ }
+ ],
+ "GL_BGRA_EXT": [
+ {
+ "texFormat": "DXGI_FORMAT_B8G8R8A8_UNORM",
+ "srvFormat": "DXGI_FORMAT_B8G8R8A8_UNORM",
+ "rtvFormat": "DXGI_FORMAT_B8G8R8A8_UNORM"
+ }
+ ],
+ "GL_COMPRESSED_R11_EAC": [
+ {
+ "texFormat": "DXGI_FORMAT_R8_UNORM",
+ "srvFormat": "DXGI_FORMAT_R8_UNORM",
+ "requirementsFcn": "OnlyFL10Plus"
+ }
+ ],
+ "GL_COMPRESSED_RG11_EAC": [
+ {
+ "texFormat": "DXGI_FORMAT_R8G8_UNORM",
+ "srvFormat": "DXGI_FORMAT_R8G8_UNORM",
+ "requirementsFcn": "OnlyFL10Plus"
+ }
+ ],
+ "GL_COMPRESSED_RGB8_ETC2": [
+ {
+ "texFormat": "DXGI_FORMAT_R8G8B8A8_UNORM",
+ "srvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM",
+ "requirementsFcn": "OnlyFL10Plus"
+ }
+ ],
+ "GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2": [
+ {
+ "texFormat": "DXGI_FORMAT_R8G8B8A8_UNORM",
+ "srvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM",
+ "requirementsFcn": "OnlyFL10Plus"
+ }
+ ],
+ "GL_COMPRESSED_RGBA8_ETC2_EAC": [
+ {
+ "texFormat": "DXGI_FORMAT_R8G8B8A8_UNORM",
+ "srvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM",
+ "requirementsFcn": "OnlyFL10Plus"
+ }
+ ],
+ "GL_COMPRESSED_RGBA_S3TC_DXT1_EXT": [
+ {
+ "texFormat": "DXGI_FORMAT_BC1_UNORM",
+ "srvFormat": "DXGI_FORMAT_BC1_UNORM"
+ }
+ ],
+ "GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE": [
+ {
+ "texFormat": "DXGI_FORMAT_BC2_UNORM",
+ "srvFormat": "DXGI_FORMAT_BC2_UNORM"
+ }
+ ],
+ "GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE": [
+ {
+ "texFormat": "DXGI_FORMAT_BC3_UNORM",
+ "srvFormat": "DXGI_FORMAT_BC3_UNORM"
+ }
+ ],
+ "GL_COMPRESSED_RGB_S3TC_DXT1_EXT": [
+ {
+ "texFormat": "DXGI_FORMAT_BC1_UNORM",
+ "srvFormat": "DXGI_FORMAT_BC1_UNORM"
+ }
+ ],
+ "GL_COMPRESSED_SIGNED_R11_EAC": [
+ {
+ "texFormat": "DXGI_FORMAT_R8_SNORM",
+ "srvFormat": "DXGI_FORMAT_R8_SNORM",
+ "requirementsFcn": "OnlyFL10Plus"
+ }
+ ],
+ "GL_COMPRESSED_SIGNED_RG11_EAC": [
+ {
+ "texFormat": "DXGI_FORMAT_R8G8_SNORM",
+ "srvFormat": "DXGI_FORMAT_R8G8_SNORM",
+ "requirementsFcn": "OnlyFL10Plus"
+ }
+ ],
+ "GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC": [
+ {
+ "texFormat": "DXGI_FORMAT_R8G8B8A8_UNORM_SRGB",
+ "srvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM_SRGB",
+ "requirementsFcn": "OnlyFL10Plus"
+ }
+ ],
+ "GL_COMPRESSED_SRGB8_ETC2": [
+ {
+ "texFormat": "DXGI_FORMAT_R8G8B8A8_UNORM_SRGB",
+ "srvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM_SRGB",
+ "requirementsFcn": "OnlyFL10Plus"
+ }
+ ],
+ "GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2": [
+ {
+ "texFormat": "DXGI_FORMAT_R8G8B8A8_UNORM_SRGB",
+ "srvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM_SRGB",
+ "requirementsFcn": "OnlyFL10Plus"
+ }
+ ],
+ "GL_DEPTH24_STENCIL8": [
+ {
+ "texFormat": "DXGI_FORMAT_R24G8_TYPELESS",
+ "srvFormat": "DXGI_FORMAT_R24_UNORM_X8_TYPELESS",
+ "dsvFormat": "DXGI_FORMAT_D24_UNORM_S8_UINT",
+ "requirementsFcn": "OnlyFL10Plus"
+ },
+ {
+ "texFormat": "DXGI_FORMAT_D24_UNORM_S8_UINT",
+ "dsvFormat": "DXGI_FORMAT_D24_UNORM_S8_UINT",
+ "requirementsFcn": "OnlyFL9_3"
+ }
+ ],
+ "GL_DEPTH32F_STENCIL8": [
+ {
+ "texFormat": "DXGI_FORMAT_R32G8X24_TYPELESS",
+ "srvFormat": "DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS",
+ "dsvFormat": "DXGI_FORMAT_D32_FLOAT_S8X24_UINT",
+ "requirementsFcn": "OnlyFL10Plus"
+ },
+ {
+ "requirementsFcn": "OnlyFL9_3"
+ }
+ ],
+ "GL_DEPTH_COMPONENT16": [
+ {
+ "texFormat": "DXGI_FORMAT_R16_TYPELESS",
+ "srvFormat": "DXGI_FORMAT_R16_UNORM",
+ "dsvFormat": "DXGI_FORMAT_D16_UNORM",
+ "requirementsFcn": "OnlyFL10Plus"
+ },
+ {
+ "texFormat": "DXGI_FORMAT_D16_UNORM",
+ "dsvFormat": "DXGI_FORMAT_D16_UNORM",
+ "requirementsFcn": "OnlyFL9_3"
+ }
+ ],
+ "GL_DEPTH_COMPONENT24": [
+ {
+ "texFormat": "DXGI_FORMAT_R24G8_TYPELESS",
+ "srvFormat": "DXGI_FORMAT_R24_UNORM_X8_TYPELESS",
+ "dsvFormat": "DXGI_FORMAT_D24_UNORM_S8_UINT",
+ "requirementsFcn": "OnlyFL10Plus"
+ },
+ {
+ "texFormat": "DXGI_FORMAT_D24_UNORM_S8_UINT",
+ "dsvFormat": "DXGI_FORMAT_D24_UNORM_S8_UINT",
+ "requirementsFcn": "OnlyFL9_3"
+ }
+ ],
+ "GL_DEPTH_COMPONENT32F": [
+ {
+ "texFormat": "DXGI_FORMAT_R32_TYPELESS",
+ "srvFormat": "DXGI_FORMAT_R32_FLOAT",
+ "dsvFormat": "DXGI_FORMAT_D32_FLOAT",
+ "requirementsFcn": "OnlyFL10Plus"
+ },
+ {
+ "requirementsFcn": "OnlyFL9_3"
+ }
+ ],
+ "GL_DEPTH_COMPONENT32_OES": [
+ {
+ "texFormat": "DXGI_FORMAT_R24G8_TYPELESS",
+ "srvFormat": "DXGI_FORMAT_R24_UNORM_X8_TYPELESS",
+ "dsvFormat": "DXGI_FORMAT_D24_UNORM_S8_UINT",
+ "requirementsFcn": "OnlyFL10Plus"
+ }
+ ],
+ "GL_ETC1_RGB8_OES": [
+ {
+ "texFormat": "DXGI_FORMAT_R8G8B8A8_UNORM",
+ "srvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM"
+ }
+ ],
+ "GL_ETC1_RGB8_LOSSY_DECODE_ANGLE": [
+ {
+ "texFormat": "DXGI_FORMAT_BC1_UNORM",
+ "srvFormat": "DXGI_FORMAT_BC1_UNORM"
+ }
+ ],
+ "GL_LUMINANCE": [
+ {
+ "texFormat": "DXGI_FORMAT_R8G8B8A8_UNORM",
+ "srvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM",
+ "rtvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM"
+ }
+ ],
+ "GL_LUMINANCE16F_EXT": [
+ {
+ "texFormat": "DXGI_FORMAT_R16G16B16A16_FLOAT",
+ "srvFormat": "DXGI_FORMAT_R16G16B16A16_FLOAT",
+ "rtvFormat": "DXGI_FORMAT_R16G16B16A16_FLOAT"
+ }
+ ],
+ "GL_LUMINANCE32F_EXT": [
+ {
+ "texFormat": "DXGI_FORMAT_R32G32B32A32_FLOAT",
+ "srvFormat": "DXGI_FORMAT_R32G32B32A32_FLOAT",
+ "rtvFormat": "DXGI_FORMAT_R32G32B32A32_FLOAT"
+ }
+ ],
+ "GL_LUMINANCE8_ALPHA8_EXT": [
+ {
+ "texFormat": "DXGI_FORMAT_R8G8B8A8_UNORM",
+ "srvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM",
+ "rtvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM"
+ }
+ ],
+ "GL_LUMINANCE8_EXT": [
+ {
+ "texFormat": "DXGI_FORMAT_R8G8B8A8_UNORM",
+ "srvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM",
+ "rtvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM"
+ }
+ ],
+ "GL_LUMINANCE_ALPHA": [
+ {
+ "texFormat": "DXGI_FORMAT_R8G8B8A8_UNORM",
+ "srvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM",
+ "rtvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM"
+ }
+ ],
+ "GL_LUMINANCE_ALPHA16F_EXT": [
+ {
+ "texFormat": "DXGI_FORMAT_R16G16B16A16_FLOAT",
+ "srvFormat": "DXGI_FORMAT_R16G16B16A16_FLOAT",
+ "rtvFormat": "DXGI_FORMAT_R16G16B16A16_FLOAT"
+ }
+ ],
+ "GL_LUMINANCE_ALPHA32F_EXT": [
+ {
+ "texFormat": "DXGI_FORMAT_R32G32B32A32_FLOAT",
+ "srvFormat": "DXGI_FORMAT_R32G32B32A32_FLOAT",
+ "rtvFormat": "DXGI_FORMAT_R32G32B32A32_FLOAT"
+ }
+ ],
+ "GL_NONE": [
+ {
+ }
+ ],
+ "GL_R11F_G11F_B10F": [
+ {
+ "texFormat": "DXGI_FORMAT_R11G11B10_FLOAT",
+ "srvFormat": "DXGI_FORMAT_R11G11B10_FLOAT",
+ "rtvFormat": "DXGI_FORMAT_R11G11B10_FLOAT"
+ }
+ ],
+ "GL_R16F": [
+ {
+ "texFormat": "DXGI_FORMAT_R16_FLOAT",
+ "srvFormat": "DXGI_FORMAT_R16_FLOAT",
+ "rtvFormat": "DXGI_FORMAT_R16_FLOAT"
+ }
+ ],
+ "GL_R16I": [
+ {
+ "texFormat": "DXGI_FORMAT_R16_SINT",
+ "srvFormat": "DXGI_FORMAT_R16_SINT",
+ "rtvFormat": "DXGI_FORMAT_R16_SINT"
+ }
+ ],
+ "GL_R16UI": [
+ {
+ "texFormat": "DXGI_FORMAT_R16_UINT",
+ "srvFormat": "DXGI_FORMAT_R16_UINT",
+ "rtvFormat": "DXGI_FORMAT_R16_UINT"
+ }
+ ],
+ "GL_R32F": [
+ {
+ "texFormat": "DXGI_FORMAT_R32_FLOAT",
+ "srvFormat": "DXGI_FORMAT_R32_FLOAT",
+ "rtvFormat": "DXGI_FORMAT_R32_FLOAT"
+ }
+ ],
+ "GL_R32I": [
+ {
+ "texFormat": "DXGI_FORMAT_R32_SINT",
+ "srvFormat": "DXGI_FORMAT_R32_SINT",
+ "rtvFormat": "DXGI_FORMAT_R32_SINT"
+ }
+ ],
+ "GL_R32UI": [
+ {
+ "texFormat": "DXGI_FORMAT_R32_UINT",
+ "srvFormat": "DXGI_FORMAT_R32_UINT",
+ "rtvFormat": "DXGI_FORMAT_R32_UINT"
+ }
+ ],
+ "GL_R8": [
+ {
+ "texFormat": "DXGI_FORMAT_R8_UNORM",
+ "srvFormat": "DXGI_FORMAT_R8_UNORM",
+ "rtvFormat": "DXGI_FORMAT_R8_UNORM"
+ }
+ ],
+ "GL_R8I": [
+ {
+ "texFormat": "DXGI_FORMAT_R8_SINT",
+ "srvFormat": "DXGI_FORMAT_R8_SINT",
+ "rtvFormat": "DXGI_FORMAT_R8_SINT"
+ }
+ ],
+ "GL_R8UI": [
+ {
+ "texFormat": "DXGI_FORMAT_R8_UINT",
+ "srvFormat": "DXGI_FORMAT_R8_UINT",
+ "rtvFormat": "DXGI_FORMAT_R8_UINT"
+ }
+ ],
+ "GL_R8_SNORM": [
+ {
+ "texFormat": "DXGI_FORMAT_R8_SNORM",
+ "srvFormat": "DXGI_FORMAT_R8_SNORM"
+ }
+ ],
+ "GL_RG16F": [
+ {
+ "texFormat": "DXGI_FORMAT_R16G16_FLOAT",
+ "srvFormat": "DXGI_FORMAT_R16G16_FLOAT",
+ "rtvFormat": "DXGI_FORMAT_R16G16_FLOAT"
+ }
+ ],
+ "GL_RG16I": [
+ {
+ "texFormat": "DXGI_FORMAT_R16G16_SINT",
+ "srvFormat": "DXGI_FORMAT_R16G16_SINT",
+ "rtvFormat": "DXGI_FORMAT_R16G16_SINT"
+ }
+ ],
+ "GL_RG16UI": [
+ {
+ "texFormat": "DXGI_FORMAT_R16G16_UINT",
+ "srvFormat": "DXGI_FORMAT_R16G16_UINT",
+ "rtvFormat": "DXGI_FORMAT_R16G16_UINT"
+ }
+ ],
+ "GL_RG32F": [
+ {
+ "texFormat": "DXGI_FORMAT_R32G32_FLOAT",
+ "srvFormat": "DXGI_FORMAT_R32G32_FLOAT",
+ "rtvFormat": "DXGI_FORMAT_R32G32_FLOAT"
+ }
+ ],
+ "GL_RG32I": [
+ {
+ "texFormat": "DXGI_FORMAT_R32G32_SINT",
+ "srvFormat": "DXGI_FORMAT_R32G32_SINT",
+ "rtvFormat": "DXGI_FORMAT_R32G32_SINT"
+ }
+ ],
+ "GL_RG32UI": [
+ {
+ "texFormat": "DXGI_FORMAT_R32G32_UINT",
+ "srvFormat": "DXGI_FORMAT_R32G32_UINT",
+ "rtvFormat": "DXGI_FORMAT_R32G32_UINT"
+ }
+ ],
+ "GL_RG8": [
+ {
+ "texFormat": "DXGI_FORMAT_R8G8_UNORM",
+ "srvFormat": "DXGI_FORMAT_R8G8_UNORM",
+ "rtvFormat": "DXGI_FORMAT_R8G8_UNORM"
+ }
+ ],
+ "GL_RG8I": [
+ {
+ "texFormat": "DXGI_FORMAT_R8G8_SINT",
+ "srvFormat": "DXGI_FORMAT_R8G8_SINT",
+ "rtvFormat": "DXGI_FORMAT_R8G8_SINT"
+ }
+ ],
+ "GL_RG8UI": [
+ {
+ "texFormat": "DXGI_FORMAT_R8G8_UINT",
+ "srvFormat": "DXGI_FORMAT_R8G8_UINT",
+ "rtvFormat": "DXGI_FORMAT_R8G8_UINT"
+ }
+ ],
+ "GL_RG8_SNORM": [
+ {
+ "texFormat": "DXGI_FORMAT_R8G8_SNORM",
+ "srvFormat": "DXGI_FORMAT_R8G8_SNORM"
+ }
+ ],
+ "GL_RGB": [
+ {
+ "texFormat": "DXGI_FORMAT_R8G8B8A8_UNORM",
+ "srvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM",
+ "rtvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM"
+ }
+ ],
+ "GL_RGB10_A2": [
+ {
+ "texFormat": "DXGI_FORMAT_R10G10B10A2_UNORM",
+ "srvFormat": "DXGI_FORMAT_R10G10B10A2_UNORM",
+ "rtvFormat": "DXGI_FORMAT_R10G10B10A2_UNORM"
+ }
+ ],
+ "GL_RGB10_A2UI": [
+ {
+ "texFormat": "DXGI_FORMAT_R10G10B10A2_UINT",
+ "srvFormat": "DXGI_FORMAT_R10G10B10A2_UINT",
+ "rtvFormat": "DXGI_FORMAT_R10G10B10A2_UINT"
+ }
+ ],
+ "GL_RGB16F": [
+ {
+ "texFormat": "DXGI_FORMAT_R16G16B16A16_FLOAT",
+ "srvFormat": "DXGI_FORMAT_R16G16B16A16_FLOAT",
+ "rtvFormat": "DXGI_FORMAT_R16G16B16A16_FLOAT"
+ }
+ ],
+ "GL_RGB16I": [
+ {
+ "texFormat": "DXGI_FORMAT_R16G16B16A16_SINT",
+ "srvFormat": "DXGI_FORMAT_R16G16B16A16_SINT",
+ "rtvFormat": "DXGI_FORMAT_R16G16B16A16_SINT"
+ }
+ ],
+ "GL_RGB16UI": [
+ {
+ "texFormat": "DXGI_FORMAT_R16G16B16A16_UINT",
+ "srvFormat": "DXGI_FORMAT_R16G16B16A16_UINT",
+ "rtvFormat": "DXGI_FORMAT_R16G16B16A16_UINT"
+ }
+ ],
+ "GL_RGB32F": [
+ {
+ "texFormat": "DXGI_FORMAT_R32G32B32A32_FLOAT",
+ "srvFormat": "DXGI_FORMAT_R32G32B32A32_FLOAT",
+ "rtvFormat": "DXGI_FORMAT_R32G32B32A32_FLOAT"
+ }
+ ],
+ "GL_RGB32I": [
+ {
+ "texFormat": "DXGI_FORMAT_R32G32B32A32_SINT",
+ "srvFormat": "DXGI_FORMAT_R32G32B32A32_SINT",
+ "rtvFormat": "DXGI_FORMAT_R32G32B32A32_SINT"
+ }
+ ],
+ "GL_RGB32UI": [
+ {
+ "texFormat": "DXGI_FORMAT_R32G32B32A32_UINT",
+ "srvFormat": "DXGI_FORMAT_R32G32B32A32_UINT",
+ "rtvFormat": "DXGI_FORMAT_R32G32B32A32_UINT"
+ }
+ ],
+ "GL_RGB565": [
+ {
+ "texFormat": "DXGI_FORMAT_R8G8B8A8_UNORM",
+ "srvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM",
+ "rtvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM",
+ "requirementsFcn": "SupportsFormat<DXGI_FORMAT_B5G6R5_UNORM,false>"
+ },
+ {
+ "texFormat": "DXGI_FORMAT_B5G6R5_UNORM",
+ "srvFormat": "DXGI_FORMAT_B5G6R5_UNORM",
+ "rtvFormat": "DXGI_FORMAT_B5G6R5_UNORM",
+ "requirementsFcn": "SupportsFormat<DXGI_FORMAT_B5G6R5_UNORM,true>"
+ }
+ ],
+ "GL_RGB5_A1": [
+ {
+ "texFormat": "DXGI_FORMAT_R8G8B8A8_UNORM",
+ "srvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM",
+ "rtvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM",
+ "requirementsFcn": "SupportsFormat<DXGI_FORMAT_B5G5R5A1_UNORM,false>"
+ },
+ {
+ "texFormat": "DXGI_FORMAT_B5G5R5A1_UNORM",
+ "srvFormat": "DXGI_FORMAT_B5G5R5A1_UNORM",
+ "rtvFormat": "DXGI_FORMAT_B5G5R5A1_UNORM",
+ "requirementsFcn": "SupportsFormat<DXGI_FORMAT_B5G5R5A1_UNORM,true>"
+ }
+ ],
+ "GL_RGB8": [
+ {
+ "texFormat": "DXGI_FORMAT_R8G8B8A8_UNORM",
+ "srvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM",
+ "rtvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM"
+ }
+ ],
+ "GL_RGB8I": [
+ {
+ "texFormat": "DXGI_FORMAT_R8G8B8A8_SINT",
+ "srvFormat": "DXGI_FORMAT_R8G8B8A8_SINT",
+ "rtvFormat": "DXGI_FORMAT_R8G8B8A8_SINT"
+ }
+ ],
+ "GL_RGB8UI": [
+ {
+ "texFormat": "DXGI_FORMAT_R8G8B8A8_UINT",
+ "srvFormat": "DXGI_FORMAT_R8G8B8A8_UINT",
+ "rtvFormat": "DXGI_FORMAT_R8G8B8A8_UINT"
+ }
+ ],
+ "GL_RGB8_SNORM": [
+ {
+ "texFormat": "DXGI_FORMAT_R8G8B8A8_SNORM",
+ "srvFormat": "DXGI_FORMAT_R8G8B8A8_SNORM"
+ }
+ ],
+ "GL_RGB9_E5": [
+ {
+ "texFormat": "DXGI_FORMAT_R9G9B9E5_SHAREDEXP",
+ "srvFormat": "DXGI_FORMAT_R9G9B9E5_SHAREDEXP"
+ }
+ ],
+ "GL_RGBA": [
+ {
+ "texFormat": "DXGI_FORMAT_R8G8B8A8_UNORM",
+ "srvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM",
+ "rtvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM"
+ }
+ ],
+ "GL_RGBA16F": [
+ {
+ "texFormat": "DXGI_FORMAT_R16G16B16A16_FLOAT",
+ "srvFormat": "DXGI_FORMAT_R16G16B16A16_FLOAT",
+ "rtvFormat": "DXGI_FORMAT_R16G16B16A16_FLOAT"
+ }
+ ],
+ "GL_RGBA16I": [
+ {
+ "texFormat": "DXGI_FORMAT_R16G16B16A16_SINT",
+ "srvFormat": "DXGI_FORMAT_R16G16B16A16_SINT",
+ "rtvFormat": "DXGI_FORMAT_R16G16B16A16_SINT"
+ }
+ ],
+ "GL_RGBA16UI": [
+ {
+ "texFormat": "DXGI_FORMAT_R16G16B16A16_UINT",
+ "srvFormat": "DXGI_FORMAT_R16G16B16A16_UINT",
+ "rtvFormat": "DXGI_FORMAT_R16G16B16A16_UINT"
+ }
+ ],
+ "GL_RGBA32F": [
+ {
+ "texFormat": "DXGI_FORMAT_R32G32B32A32_FLOAT",
+ "srvFormat": "DXGI_FORMAT_R32G32B32A32_FLOAT",
+ "rtvFormat": "DXGI_FORMAT_R32G32B32A32_FLOAT"
+ }
+ ],
+ "GL_RGBA32I": [
+ {
+ "texFormat": "DXGI_FORMAT_R32G32B32A32_SINT",
+ "srvFormat": "DXGI_FORMAT_R32G32B32A32_SINT",
+ "rtvFormat": "DXGI_FORMAT_R32G32B32A32_SINT"
+ }
+ ],
+ "GL_RGBA32UI": [
+ {
+ "texFormat": "DXGI_FORMAT_R32G32B32A32_UINT",
+ "srvFormat": "DXGI_FORMAT_R32G32B32A32_UINT",
+ "rtvFormat": "DXGI_FORMAT_R32G32B32A32_UINT"
+ }
+ ],
+ "GL_RGBA4": [
+ {
+ "texFormat": "DXGI_FORMAT_R8G8B8A8_UNORM",
+ "srvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM",
+ "rtvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM",
+ "requirementsFcn": "SupportsFormat<DXGI_FORMAT_B4G4R4A4_UNORM,false>"
+ },
+ {
+ "texFormat": "DXGI_FORMAT_B4G4R4A4_UNORM",
+ "srvFormat": "DXGI_FORMAT_B4G4R4A4_UNORM",
+ "rtvFormat": "DXGI_FORMAT_B4G4R4A4_UNORM",
+ "requirementsFcn": "SupportsFormat<DXGI_FORMAT_B4G4R4A4_UNORM,true>"
+ }
+ ],
+ "GL_RGBA8": [
+ {
+ "texFormat": "DXGI_FORMAT_R8G8B8A8_UNORM",
+ "srvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM",
+ "rtvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM"
+ }
+ ],
+ "GL_RGBA8I": [
+ {
+ "texFormat": "DXGI_FORMAT_R8G8B8A8_SINT",
+ "srvFormat": "DXGI_FORMAT_R8G8B8A8_SINT",
+ "rtvFormat": "DXGI_FORMAT_R8G8B8A8_SINT"
+ }
+ ],
+ "GL_RGBA8UI": [
+ {
+ "texFormat": "DXGI_FORMAT_R8G8B8A8_UINT",
+ "srvFormat": "DXGI_FORMAT_R8G8B8A8_UINT",
+ "rtvFormat": "DXGI_FORMAT_R8G8B8A8_UINT"
+ }
+ ],
+ "GL_RGBA8_SNORM": [
+ {
+ "texFormat": "DXGI_FORMAT_R8G8B8A8_SNORM",
+ "srvFormat": "DXGI_FORMAT_R8G8B8A8_SNORM"
+ }
+ ],
+ "GL_SRGB8": [
+ {
+ "texFormat": "DXGI_FORMAT_R8G8B8A8_UNORM_SRGB",
+ "srvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM_SRGB"
+ }
+ ],
+ "GL_SRGB8_ALPHA8": [
+ {
+ "texFormat": "DXGI_FORMAT_R8G8B8A8_UNORM_SRGB",
+ "srvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM_SRGB",
+ "rtvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM_SRGB"
+ }
+ ],
+ "GL_STENCIL_INDEX8": [
+ {
+ "texFormat": "DXGI_FORMAT_R24G8_TYPELESS",
+ "srvFormat": "DXGI_FORMAT_X24_TYPELESS_G8_UINT",
+ "dsvFormat": "DXGI_FORMAT_D24_UNORM_S8_UINT",
+ "requirementsFcn": "OnlyFL10Plus"
+ },
+ {
+ "texFormat": "DXGI_FORMAT_D24_UNORM_S8_UINT",
+ "dsvFormat": "DXGI_FORMAT_D24_UNORM_S8_UINT",
+ "requirementsFcn": "OnlyFL9_3"
+ }
+ ]
+}
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/texture_format_table.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/texture_format_table.h
new file mode 100644
index 0000000000..1606a28a73
--- /dev/null
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/texture_format_table.h
@@ -0,0 +1,64 @@
+//
+// 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.
+//
+// texture_format_table:
+// Queries for full textureFormat information based on internalFormat
+//
+
+#ifndef LIBANGLE_RENDERER_D3D_D3D11_TEXTUREFORMATTABLE_H_
+#define LIBANGLE_RENDERER_D3D_D3D11_TEXTUREFORMATTABLE_H_
+
+#include <map>
+
+#include "common/platform.h"
+#include "libANGLE/renderer/d3d/formatutilsD3D.h"
+#include "libANGLE/renderer/d3d/d3d11/Renderer11.h"
+
+namespace rx
+{
+
+namespace d3d11
+{
+
+struct LoadImageFunctionInfo
+{
+ LoadImageFunctionInfo() : loadFunction(nullptr), requiresConversion(false) {}
+ LoadImageFunctionInfo(LoadImageFunction loadFunction, bool requiresConversion)
+ : loadFunction(loadFunction), requiresConversion(requiresConversion)
+ {
+ }
+
+ LoadImageFunction loadFunction;
+ bool requiresConversion;
+};
+
+struct TextureFormat
+{
+ TextureFormat();
+
+ DXGI_FORMAT texFormat;
+ DXGI_FORMAT srvFormat;
+ DXGI_FORMAT rtvFormat;
+ DXGI_FORMAT dsvFormat;
+ DXGI_FORMAT renderFormat;
+
+ DXGI_FORMAT swizzleTexFormat;
+ DXGI_FORMAT swizzleSRVFormat;
+ DXGI_FORMAT swizzleRTVFormat;
+
+ InitializeTextureDataFunction dataInitializerFunction;
+ typedef std::map<GLenum, LoadImageFunctionInfo> LoadFunctionMap;
+
+ LoadFunctionMap loadFunctions;
+};
+
+const TextureFormat &GetTextureFormatInfo(GLenum internalformat,
+ const Renderer11DeviceCaps &renderer11DeviceCaps);
+
+} // namespace d3d11
+
+} // namespace rx
+
+#endif // LIBANGLE_RENDERER_D3D_D3D11_TEXTUREFORMATTABLE_H_
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/texture_format_table_autogen.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/texture_format_table_autogen.cpp
new file mode 100644
index 0000000000..0b214c9756
--- /dev/null
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/texture_format_table_autogen.cpp
@@ -0,0 +1,1791 @@
+// GENERATED FILE - DO NOT EDIT.
+// Generated by gen_texture_format_table.py using data from texture_format_data.json
+//
+// 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.
+//
+// texture_format_table:
+// Queries for full textureFormat information based in internalFormat
+//
+
+#include "libANGLE/renderer/d3d/d3d11/texture_format_table.h"
+
+#include "libANGLE/renderer/d3d/d3d11/formatutils11.h"
+#include "libANGLE/renderer/d3d/d3d11/internal_format_initializer_table.h"
+#include "libANGLE/renderer/d3d/d3d11/load_functions_table.h"
+#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h"
+#include "libANGLE/renderer/d3d/d3d11/swizzle_format_info.h"
+#include "libANGLE/renderer/d3d/loadimage.h"
+
+namespace rx
+{
+
+namespace d3d11
+{
+
+namespace
+{
+
+typedef bool (*FormatSupportFunction)(const Renderer11DeviceCaps &);
+
+bool AnyDevice(const Renderer11DeviceCaps &deviceCaps)
+{
+ return true;
+}
+
+bool OnlyFL10Plus(const Renderer11DeviceCaps &deviceCaps)
+{
+ return (deviceCaps.featureLevel >= D3D_FEATURE_LEVEL_10_0);
+}
+
+bool OnlyFL9_3(const Renderer11DeviceCaps &deviceCaps)
+{
+ return (deviceCaps.featureLevel == D3D_FEATURE_LEVEL_9_3);
+}
+
+template <DXGI_FORMAT format, bool requireSupport>
+bool SupportsFormat(const Renderer11DeviceCaps &deviceCaps)
+{
+ // Must support texture, SRV and RTV support
+ UINT mustSupport = D3D11_FORMAT_SUPPORT_TEXTURE2D | D3D11_FORMAT_SUPPORT_TEXTURECUBE |
+ D3D11_FORMAT_SUPPORT_SHADER_SAMPLE | D3D11_FORMAT_SUPPORT_MIP |
+ D3D11_FORMAT_SUPPORT_RENDER_TARGET;
+
+ if (d3d11_gl::GetMaximumClientVersion(deviceCaps.featureLevel) > 2)
+ {
+ mustSupport |= D3D11_FORMAT_SUPPORT_TEXTURE3D;
+ }
+
+ bool fullSupport = false;
+ if (format == DXGI_FORMAT_B5G6R5_UNORM)
+ {
+ // All hardware that supports DXGI_FORMAT_B5G6R5_UNORM should support autogen mipmaps, but
+ // check anyway.
+ mustSupport |= D3D11_FORMAT_SUPPORT_MIP_AUTOGEN;
+ fullSupport = ((deviceCaps.B5G6R5support & mustSupport) == mustSupport);
+ }
+ else if (format == DXGI_FORMAT_B4G4R4A4_UNORM)
+ {
+ fullSupport = ((deviceCaps.B4G4R4A4support & mustSupport) == mustSupport);
+ }
+ else if (format == DXGI_FORMAT_B5G5R5A1_UNORM)
+ {
+ fullSupport = ((deviceCaps.B5G5R5A1support & mustSupport) == mustSupport);
+ }
+ else
+ {
+ UNREACHABLE();
+ return false;
+ }
+
+ // This 'SupportsFormat' function is used by individual entries in the D3D11 Format Map below,
+ // which maps GL formats to DXGI formats.
+ if (requireSupport)
+ {
+ // This means that ANGLE would like to use the entry in the map if the inputted DXGI format
+ // *IS* supported.
+ // e.g. the entry might map GL_RGB5_A1 to DXGI_FORMAT_B5G5R5A1, which should only be used if
+ // DXGI_FORMAT_B5G5R5A1 is supported.
+ // In this case, we should only return 'true' if the format *IS* supported.
+ return fullSupport;
+ }
+ else
+ {
+ // This means that ANGLE would like to use the entry in the map if the inputted DXGI format
+ // *ISN'T* supported.
+ // This might be a fallback entry. e.g. for ANGLE to use DXGI_FORMAT_R8G8B8A8_UNORM if
+ // DXGI_FORMAT_B5G5R5A1 isn't supported.
+ // In this case, we should only return 'true' if the format *ISN'T* supported.
+ return !fullSupport;
+ }
+}
+
+// End Format Support Functions
+
+// For sized GL internal formats, there are several possible corresponding D3D11 formats depending
+// on device capabilities.
+// This function allows querying for the DXGI texture formats to use for textures, SRVs, RTVs and
+// DSVs given a GL internal format.
+const TextureFormat GetD3D11FormatInfo(GLenum internalFormat,
+ DXGI_FORMAT texFormat,
+ DXGI_FORMAT srvFormat,
+ DXGI_FORMAT rtvFormat,
+ DXGI_FORMAT dsvFormat)
+{
+ TextureFormat info;
+ info.texFormat = texFormat;
+ info.srvFormat = srvFormat;
+ info.rtvFormat = rtvFormat;
+ info.dsvFormat = dsvFormat;
+
+ // Given a GL internal format, the renderFormat is the DSV format if it is depth- or
+ // stencil-renderable,
+ // the RTV format if it is color-renderable, and the (nonrenderable) texture format otherwise.
+ if (dsvFormat != DXGI_FORMAT_UNKNOWN)
+ {
+ info.renderFormat = dsvFormat;
+ }
+ else if (rtvFormat != DXGI_FORMAT_UNKNOWN)
+ {
+ info.renderFormat = rtvFormat;
+ }
+ else if (texFormat != DXGI_FORMAT_UNKNOWN)
+ {
+ info.renderFormat = texFormat;
+ }
+ else
+ {
+ info.renderFormat = DXGI_FORMAT_UNKNOWN;
+ }
+
+ // Compute the swizzle formats
+ const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat);
+ if (internalFormat != GL_NONE && formatInfo.pixelBytes > 0)
+ {
+ if (formatInfo.componentCount != 4 || texFormat == DXGI_FORMAT_UNKNOWN ||
+ srvFormat == DXGI_FORMAT_UNKNOWN || rtvFormat == DXGI_FORMAT_UNKNOWN)
+ {
+ // Get the maximum sized component
+ unsigned int maxBits = 1;
+ if (formatInfo.compressed)
+ {
+ unsigned int compressedBitsPerBlock = formatInfo.pixelBytes * 8;
+ unsigned int blockSize =
+ formatInfo.compressedBlockWidth * formatInfo.compressedBlockHeight;
+ maxBits = std::max(compressedBitsPerBlock / blockSize, maxBits);
+ }
+ else
+ {
+ maxBits = std::max(maxBits, formatInfo.alphaBits);
+ maxBits = std::max(maxBits, formatInfo.redBits);
+ maxBits = std::max(maxBits, formatInfo.greenBits);
+ maxBits = std::max(maxBits, formatInfo.blueBits);
+ maxBits = std::max(maxBits, formatInfo.luminanceBits);
+ maxBits = std::max(maxBits, formatInfo.depthBits);
+ }
+
+ maxBits = roundUp(maxBits, 8U);
+
+ const SwizzleFormatInfo &swizzleInfo =
+ GetSwizzleFormatInfo(maxBits, formatInfo.componentType);
+ info.swizzleTexFormat = swizzleInfo.mTexFormat;
+ info.swizzleSRVFormat = swizzleInfo.mSRVFormat;
+ info.swizzleRTVFormat = swizzleInfo.mRTVFormat;
+ }
+ else
+ {
+ // The original texture format is suitable for swizzle operations
+ info.swizzleTexFormat = texFormat;
+ info.swizzleSRVFormat = srvFormat;
+ info.swizzleRTVFormat = rtvFormat;
+ }
+ }
+ else
+ {
+ // Not possible to swizzle with this texture format since it is either unsized or GL_NONE
+ info.swizzleTexFormat = DXGI_FORMAT_UNKNOWN;
+ info.swizzleSRVFormat = DXGI_FORMAT_UNKNOWN;
+ info.swizzleRTVFormat = DXGI_FORMAT_UNKNOWN;
+ }
+
+ // Check if there is an initialization function for this texture format
+ info.dataInitializerFunction = GetInternalFormatInitializer(internalFormat, texFormat);
+ // Gather all the load functions for this internal format
+ info.loadFunctions = GetLoadFunctionsMap(internalFormat, texFormat);
+
+ ASSERT(info.loadFunctions.size() != 0 || internalFormat == GL_NONE);
+
+ return info;
+}
+
+} // namespace
+
+TextureFormat::TextureFormat()
+ : texFormat(DXGI_FORMAT_UNKNOWN),
+ srvFormat(DXGI_FORMAT_UNKNOWN),
+ rtvFormat(DXGI_FORMAT_UNKNOWN),
+ dsvFormat(DXGI_FORMAT_UNKNOWN),
+ renderFormat(DXGI_FORMAT_UNKNOWN),
+ swizzleTexFormat(DXGI_FORMAT_UNKNOWN),
+ swizzleSRVFormat(DXGI_FORMAT_UNKNOWN),
+ swizzleRTVFormat(DXGI_FORMAT_UNKNOWN),
+ dataInitializerFunction(NULL),
+ loadFunctions()
+{
+}
+
+const TextureFormat &GetTextureFormatInfo(GLenum internalFormat,
+ const Renderer11DeviceCaps &renderer11DeviceCaps)
+{
+ // clang-format off
+ switch (internalFormat)
+ {
+ case GL_ALPHA:
+ {
+ if (OnlyFL10Plus(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_A8_UNORM,
+ DXGI_FORMAT_A8_UNORM,
+ DXGI_FORMAT_A8_UNORM,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else if (OnlyFL9_3(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R8G8B8A8_UNORM,
+ DXGI_FORMAT_R8G8B8A8_UNORM,
+ DXGI_FORMAT_R8G8B8A8_UNORM,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_ALPHA16F_EXT:
+ {
+ if (AnyDevice(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R16G16B16A16_FLOAT,
+ DXGI_FORMAT_R16G16B16A16_FLOAT,
+ DXGI_FORMAT_R16G16B16A16_FLOAT,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_ALPHA32F_EXT:
+ {
+ if (AnyDevice(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R32G32B32A32_FLOAT,
+ DXGI_FORMAT_R32G32B32A32_FLOAT,
+ DXGI_FORMAT_R32G32B32A32_FLOAT,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_ALPHA8_EXT:
+ {
+ if (OnlyFL10Plus(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_A8_UNORM,
+ DXGI_FORMAT_A8_UNORM,
+ DXGI_FORMAT_A8_UNORM,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else if (OnlyFL9_3(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R8G8B8A8_UNORM,
+ DXGI_FORMAT_R8G8B8A8_UNORM,
+ DXGI_FORMAT_R8G8B8A8_UNORM,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_BGR5_A1_ANGLEX:
+ {
+ if (AnyDevice(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_B8G8R8A8_UNORM,
+ DXGI_FORMAT_B8G8R8A8_UNORM,
+ DXGI_FORMAT_B8G8R8A8_UNORM,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_BGRA4_ANGLEX:
+ {
+ if (AnyDevice(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_B8G8R8A8_UNORM,
+ DXGI_FORMAT_B8G8R8A8_UNORM,
+ DXGI_FORMAT_B8G8R8A8_UNORM,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_BGRA8_EXT:
+ {
+ if (AnyDevice(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_B8G8R8A8_UNORM,
+ DXGI_FORMAT_B8G8R8A8_UNORM,
+ DXGI_FORMAT_B8G8R8A8_UNORM,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_BGRA_EXT:
+ {
+ if (AnyDevice(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_B8G8R8A8_UNORM,
+ DXGI_FORMAT_B8G8R8A8_UNORM,
+ DXGI_FORMAT_B8G8R8A8_UNORM,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_COMPRESSED_R11_EAC:
+ {
+ if (OnlyFL10Plus(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R8_UNORM,
+ DXGI_FORMAT_R8_UNORM,
+ DXGI_FORMAT_UNKNOWN,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_COMPRESSED_RG11_EAC:
+ {
+ if (OnlyFL10Plus(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R8G8_UNORM,
+ DXGI_FORMAT_R8G8_UNORM,
+ DXGI_FORMAT_UNKNOWN,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_COMPRESSED_RGB8_ETC2:
+ {
+ if (OnlyFL10Plus(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R8G8B8A8_UNORM,
+ DXGI_FORMAT_R8G8B8A8_UNORM,
+ DXGI_FORMAT_UNKNOWN,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
+ {
+ if (OnlyFL10Plus(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R8G8B8A8_UNORM,
+ DXGI_FORMAT_R8G8B8A8_UNORM,
+ DXGI_FORMAT_UNKNOWN,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_COMPRESSED_RGBA8_ETC2_EAC:
+ {
+ if (OnlyFL10Plus(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R8G8B8A8_UNORM,
+ DXGI_FORMAT_R8G8B8A8_UNORM,
+ DXGI_FORMAT_UNKNOWN,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
+ {
+ if (AnyDevice(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_BC1_UNORM,
+ DXGI_FORMAT_BC1_UNORM,
+ DXGI_FORMAT_UNKNOWN,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
+ {
+ if (AnyDevice(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_BC2_UNORM,
+ DXGI_FORMAT_BC2_UNORM,
+ DXGI_FORMAT_UNKNOWN,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
+ {
+ if (AnyDevice(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_BC3_UNORM,
+ DXGI_FORMAT_BC3_UNORM,
+ DXGI_FORMAT_UNKNOWN,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
+ {
+ if (AnyDevice(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_BC1_UNORM,
+ DXGI_FORMAT_BC1_UNORM,
+ DXGI_FORMAT_UNKNOWN,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_COMPRESSED_SIGNED_R11_EAC:
+ {
+ if (OnlyFL10Plus(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R8_SNORM,
+ DXGI_FORMAT_R8_SNORM,
+ DXGI_FORMAT_UNKNOWN,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_COMPRESSED_SIGNED_RG11_EAC:
+ {
+ if (OnlyFL10Plus(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R8G8_SNORM,
+ DXGI_FORMAT_R8G8_SNORM,
+ DXGI_FORMAT_UNKNOWN,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
+ {
+ if (OnlyFL10Plus(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R8G8B8A8_UNORM_SRGB,
+ DXGI_FORMAT_R8G8B8A8_UNORM_SRGB,
+ DXGI_FORMAT_UNKNOWN,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_COMPRESSED_SRGB8_ETC2:
+ {
+ if (OnlyFL10Plus(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R8G8B8A8_UNORM_SRGB,
+ DXGI_FORMAT_R8G8B8A8_UNORM_SRGB,
+ DXGI_FORMAT_UNKNOWN,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
+ {
+ if (OnlyFL10Plus(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R8G8B8A8_UNORM_SRGB,
+ DXGI_FORMAT_R8G8B8A8_UNORM_SRGB,
+ DXGI_FORMAT_UNKNOWN,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_DEPTH24_STENCIL8:
+ {
+ if (OnlyFL9_3(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_D24_UNORM_S8_UINT,
+ DXGI_FORMAT_UNKNOWN,
+ DXGI_FORMAT_UNKNOWN,
+ DXGI_FORMAT_D24_UNORM_S8_UINT);
+ return textureFormat;
+ }
+ else if (OnlyFL10Plus(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R24G8_TYPELESS,
+ DXGI_FORMAT_R24_UNORM_X8_TYPELESS,
+ DXGI_FORMAT_UNKNOWN,
+ DXGI_FORMAT_D24_UNORM_S8_UINT);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_DEPTH32F_STENCIL8:
+ {
+ if (OnlyFL9_3(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_UNKNOWN,
+ DXGI_FORMAT_UNKNOWN,
+ DXGI_FORMAT_UNKNOWN,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else if (OnlyFL10Plus(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R32G8X24_TYPELESS,
+ DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS,
+ DXGI_FORMAT_UNKNOWN,
+ DXGI_FORMAT_D32_FLOAT_S8X24_UINT);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_DEPTH_COMPONENT16:
+ {
+ if (OnlyFL9_3(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_D16_UNORM,
+ DXGI_FORMAT_UNKNOWN,
+ DXGI_FORMAT_UNKNOWN,
+ DXGI_FORMAT_D16_UNORM);
+ return textureFormat;
+ }
+ else if (OnlyFL10Plus(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R16_TYPELESS,
+ DXGI_FORMAT_R16_UNORM,
+ DXGI_FORMAT_UNKNOWN,
+ DXGI_FORMAT_D16_UNORM);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_DEPTH_COMPONENT24:
+ {
+ if (OnlyFL9_3(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_D24_UNORM_S8_UINT,
+ DXGI_FORMAT_UNKNOWN,
+ DXGI_FORMAT_UNKNOWN,
+ DXGI_FORMAT_D24_UNORM_S8_UINT);
+ return textureFormat;
+ }
+ else if (OnlyFL10Plus(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R24G8_TYPELESS,
+ DXGI_FORMAT_R24_UNORM_X8_TYPELESS,
+ DXGI_FORMAT_UNKNOWN,
+ DXGI_FORMAT_D24_UNORM_S8_UINT);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_DEPTH_COMPONENT32F:
+ {
+ if (OnlyFL9_3(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_UNKNOWN,
+ DXGI_FORMAT_UNKNOWN,
+ DXGI_FORMAT_UNKNOWN,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else if (OnlyFL10Plus(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R32_TYPELESS,
+ DXGI_FORMAT_R32_FLOAT,
+ DXGI_FORMAT_UNKNOWN,
+ DXGI_FORMAT_D32_FLOAT);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_DEPTH_COMPONENT32_OES:
+ {
+ if (OnlyFL10Plus(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R24G8_TYPELESS,
+ DXGI_FORMAT_R24_UNORM_X8_TYPELESS,
+ DXGI_FORMAT_UNKNOWN,
+ DXGI_FORMAT_D24_UNORM_S8_UINT);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_ETC1_RGB8_LOSSY_DECODE_ANGLE:
+ {
+ if (AnyDevice(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_BC1_UNORM,
+ DXGI_FORMAT_BC1_UNORM,
+ DXGI_FORMAT_UNKNOWN,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_ETC1_RGB8_OES:
+ {
+ if (AnyDevice(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R8G8B8A8_UNORM,
+ DXGI_FORMAT_R8G8B8A8_UNORM,
+ DXGI_FORMAT_UNKNOWN,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_LUMINANCE:
+ {
+ if (AnyDevice(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R8G8B8A8_UNORM,
+ DXGI_FORMAT_R8G8B8A8_UNORM,
+ DXGI_FORMAT_R8G8B8A8_UNORM,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_LUMINANCE16F_EXT:
+ {
+ if (AnyDevice(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R16G16B16A16_FLOAT,
+ DXGI_FORMAT_R16G16B16A16_FLOAT,
+ DXGI_FORMAT_R16G16B16A16_FLOAT,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_LUMINANCE32F_EXT:
+ {
+ if (AnyDevice(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R32G32B32A32_FLOAT,
+ DXGI_FORMAT_R32G32B32A32_FLOAT,
+ DXGI_FORMAT_R32G32B32A32_FLOAT,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_LUMINANCE8_ALPHA8_EXT:
+ {
+ if (AnyDevice(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R8G8B8A8_UNORM,
+ DXGI_FORMAT_R8G8B8A8_UNORM,
+ DXGI_FORMAT_R8G8B8A8_UNORM,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_LUMINANCE8_EXT:
+ {
+ if (AnyDevice(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R8G8B8A8_UNORM,
+ DXGI_FORMAT_R8G8B8A8_UNORM,
+ DXGI_FORMAT_R8G8B8A8_UNORM,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_LUMINANCE_ALPHA:
+ {
+ if (AnyDevice(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R8G8B8A8_UNORM,
+ DXGI_FORMAT_R8G8B8A8_UNORM,
+ DXGI_FORMAT_R8G8B8A8_UNORM,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_LUMINANCE_ALPHA16F_EXT:
+ {
+ if (AnyDevice(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R16G16B16A16_FLOAT,
+ DXGI_FORMAT_R16G16B16A16_FLOAT,
+ DXGI_FORMAT_R16G16B16A16_FLOAT,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_LUMINANCE_ALPHA32F_EXT:
+ {
+ if (AnyDevice(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R32G32B32A32_FLOAT,
+ DXGI_FORMAT_R32G32B32A32_FLOAT,
+ DXGI_FORMAT_R32G32B32A32_FLOAT,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_NONE:
+ {
+ if (AnyDevice(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_UNKNOWN,
+ DXGI_FORMAT_UNKNOWN,
+ DXGI_FORMAT_UNKNOWN,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_R11F_G11F_B10F:
+ {
+ if (AnyDevice(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R11G11B10_FLOAT,
+ DXGI_FORMAT_R11G11B10_FLOAT,
+ DXGI_FORMAT_R11G11B10_FLOAT,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_R16F:
+ {
+ if (AnyDevice(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R16_FLOAT,
+ DXGI_FORMAT_R16_FLOAT,
+ DXGI_FORMAT_R16_FLOAT,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_R16I:
+ {
+ if (AnyDevice(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R16_SINT,
+ DXGI_FORMAT_R16_SINT,
+ DXGI_FORMAT_R16_SINT,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_R16UI:
+ {
+ if (AnyDevice(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R16_UINT,
+ DXGI_FORMAT_R16_UINT,
+ DXGI_FORMAT_R16_UINT,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_R32F:
+ {
+ if (AnyDevice(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R32_FLOAT,
+ DXGI_FORMAT_R32_FLOAT,
+ DXGI_FORMAT_R32_FLOAT,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_R32I:
+ {
+ if (AnyDevice(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R32_SINT,
+ DXGI_FORMAT_R32_SINT,
+ DXGI_FORMAT_R32_SINT,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_R32UI:
+ {
+ if (AnyDevice(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R32_UINT,
+ DXGI_FORMAT_R32_UINT,
+ DXGI_FORMAT_R32_UINT,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_R8:
+ {
+ if (AnyDevice(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R8_UNORM,
+ DXGI_FORMAT_R8_UNORM,
+ DXGI_FORMAT_R8_UNORM,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_R8I:
+ {
+ if (AnyDevice(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R8_SINT,
+ DXGI_FORMAT_R8_SINT,
+ DXGI_FORMAT_R8_SINT,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_R8UI:
+ {
+ if (AnyDevice(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R8_UINT,
+ DXGI_FORMAT_R8_UINT,
+ DXGI_FORMAT_R8_UINT,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_R8_SNORM:
+ {
+ if (AnyDevice(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R8_SNORM,
+ DXGI_FORMAT_R8_SNORM,
+ DXGI_FORMAT_UNKNOWN,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_RG16F:
+ {
+ if (AnyDevice(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R16G16_FLOAT,
+ DXGI_FORMAT_R16G16_FLOAT,
+ DXGI_FORMAT_R16G16_FLOAT,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_RG16I:
+ {
+ if (AnyDevice(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R16G16_SINT,
+ DXGI_FORMAT_R16G16_SINT,
+ DXGI_FORMAT_R16G16_SINT,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_RG16UI:
+ {
+ if (AnyDevice(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R16G16_UINT,
+ DXGI_FORMAT_R16G16_UINT,
+ DXGI_FORMAT_R16G16_UINT,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_RG32F:
+ {
+ if (AnyDevice(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R32G32_FLOAT,
+ DXGI_FORMAT_R32G32_FLOAT,
+ DXGI_FORMAT_R32G32_FLOAT,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_RG32I:
+ {
+ if (AnyDevice(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R32G32_SINT,
+ DXGI_FORMAT_R32G32_SINT,
+ DXGI_FORMAT_R32G32_SINT,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_RG32UI:
+ {
+ if (AnyDevice(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R32G32_UINT,
+ DXGI_FORMAT_R32G32_UINT,
+ DXGI_FORMAT_R32G32_UINT,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_RG8:
+ {
+ if (AnyDevice(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R8G8_UNORM,
+ DXGI_FORMAT_R8G8_UNORM,
+ DXGI_FORMAT_R8G8_UNORM,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_RG8I:
+ {
+ if (AnyDevice(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R8G8_SINT,
+ DXGI_FORMAT_R8G8_SINT,
+ DXGI_FORMAT_R8G8_SINT,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_RG8UI:
+ {
+ if (AnyDevice(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R8G8_UINT,
+ DXGI_FORMAT_R8G8_UINT,
+ DXGI_FORMAT_R8G8_UINT,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_RG8_SNORM:
+ {
+ if (AnyDevice(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R8G8_SNORM,
+ DXGI_FORMAT_R8G8_SNORM,
+ DXGI_FORMAT_UNKNOWN,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_RGB:
+ {
+ if (AnyDevice(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R8G8B8A8_UNORM,
+ DXGI_FORMAT_R8G8B8A8_UNORM,
+ DXGI_FORMAT_R8G8B8A8_UNORM,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_RGB10_A2:
+ {
+ if (AnyDevice(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R10G10B10A2_UNORM,
+ DXGI_FORMAT_R10G10B10A2_UNORM,
+ DXGI_FORMAT_R10G10B10A2_UNORM,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_RGB10_A2UI:
+ {
+ if (AnyDevice(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R10G10B10A2_UINT,
+ DXGI_FORMAT_R10G10B10A2_UINT,
+ DXGI_FORMAT_R10G10B10A2_UINT,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_RGB16F:
+ {
+ if (AnyDevice(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R16G16B16A16_FLOAT,
+ DXGI_FORMAT_R16G16B16A16_FLOAT,
+ DXGI_FORMAT_R16G16B16A16_FLOAT,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_RGB16I:
+ {
+ if (AnyDevice(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R16G16B16A16_SINT,
+ DXGI_FORMAT_R16G16B16A16_SINT,
+ DXGI_FORMAT_R16G16B16A16_SINT,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_RGB16UI:
+ {
+ if (AnyDevice(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R16G16B16A16_UINT,
+ DXGI_FORMAT_R16G16B16A16_UINT,
+ DXGI_FORMAT_R16G16B16A16_UINT,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_RGB32F:
+ {
+ if (AnyDevice(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R32G32B32A32_FLOAT,
+ DXGI_FORMAT_R32G32B32A32_FLOAT,
+ DXGI_FORMAT_R32G32B32A32_FLOAT,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_RGB32I:
+ {
+ if (AnyDevice(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R32G32B32A32_SINT,
+ DXGI_FORMAT_R32G32B32A32_SINT,
+ DXGI_FORMAT_R32G32B32A32_SINT,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_RGB32UI:
+ {
+ if (AnyDevice(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R32G32B32A32_UINT,
+ DXGI_FORMAT_R32G32B32A32_UINT,
+ DXGI_FORMAT_R32G32B32A32_UINT,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_RGB565:
+ {
+ if (SupportsFormat<DXGI_FORMAT_B5G6R5_UNORM,false>(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R8G8B8A8_UNORM,
+ DXGI_FORMAT_R8G8B8A8_UNORM,
+ DXGI_FORMAT_R8G8B8A8_UNORM,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else if (SupportsFormat<DXGI_FORMAT_B5G6R5_UNORM,true>(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_B5G6R5_UNORM,
+ DXGI_FORMAT_B5G6R5_UNORM,
+ DXGI_FORMAT_B5G6R5_UNORM,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_RGB5_A1:
+ {
+ if (SupportsFormat<DXGI_FORMAT_B5G5R5A1_UNORM,false>(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R8G8B8A8_UNORM,
+ DXGI_FORMAT_R8G8B8A8_UNORM,
+ DXGI_FORMAT_R8G8B8A8_UNORM,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else if (SupportsFormat<DXGI_FORMAT_B5G5R5A1_UNORM,true>(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_B5G5R5A1_UNORM,
+ DXGI_FORMAT_B5G5R5A1_UNORM,
+ DXGI_FORMAT_B5G5R5A1_UNORM,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_RGB8:
+ {
+ if (AnyDevice(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R8G8B8A8_UNORM,
+ DXGI_FORMAT_R8G8B8A8_UNORM,
+ DXGI_FORMAT_R8G8B8A8_UNORM,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_RGB8I:
+ {
+ if (AnyDevice(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R8G8B8A8_SINT,
+ DXGI_FORMAT_R8G8B8A8_SINT,
+ DXGI_FORMAT_R8G8B8A8_SINT,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_RGB8UI:
+ {
+ if (AnyDevice(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R8G8B8A8_UINT,
+ DXGI_FORMAT_R8G8B8A8_UINT,
+ DXGI_FORMAT_R8G8B8A8_UINT,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_RGB8_SNORM:
+ {
+ if (AnyDevice(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R8G8B8A8_SNORM,
+ DXGI_FORMAT_R8G8B8A8_SNORM,
+ DXGI_FORMAT_UNKNOWN,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_RGB9_E5:
+ {
+ if (AnyDevice(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R9G9B9E5_SHAREDEXP,
+ DXGI_FORMAT_R9G9B9E5_SHAREDEXP,
+ DXGI_FORMAT_UNKNOWN,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_RGBA:
+ {
+ if (AnyDevice(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R8G8B8A8_UNORM,
+ DXGI_FORMAT_R8G8B8A8_UNORM,
+ DXGI_FORMAT_R8G8B8A8_UNORM,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_RGBA16F:
+ {
+ if (AnyDevice(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R16G16B16A16_FLOAT,
+ DXGI_FORMAT_R16G16B16A16_FLOAT,
+ DXGI_FORMAT_R16G16B16A16_FLOAT,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_RGBA16I:
+ {
+ if (AnyDevice(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R16G16B16A16_SINT,
+ DXGI_FORMAT_R16G16B16A16_SINT,
+ DXGI_FORMAT_R16G16B16A16_SINT,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_RGBA16UI:
+ {
+ if (AnyDevice(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R16G16B16A16_UINT,
+ DXGI_FORMAT_R16G16B16A16_UINT,
+ DXGI_FORMAT_R16G16B16A16_UINT,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_RGBA32F:
+ {
+ if (AnyDevice(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R32G32B32A32_FLOAT,
+ DXGI_FORMAT_R32G32B32A32_FLOAT,
+ DXGI_FORMAT_R32G32B32A32_FLOAT,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_RGBA32I:
+ {
+ if (AnyDevice(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R32G32B32A32_SINT,
+ DXGI_FORMAT_R32G32B32A32_SINT,
+ DXGI_FORMAT_R32G32B32A32_SINT,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_RGBA32UI:
+ {
+ if (AnyDevice(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R32G32B32A32_UINT,
+ DXGI_FORMAT_R32G32B32A32_UINT,
+ DXGI_FORMAT_R32G32B32A32_UINT,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_RGBA4:
+ {
+ if (SupportsFormat<DXGI_FORMAT_B4G4R4A4_UNORM,false>(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R8G8B8A8_UNORM,
+ DXGI_FORMAT_R8G8B8A8_UNORM,
+ DXGI_FORMAT_R8G8B8A8_UNORM,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else if (SupportsFormat<DXGI_FORMAT_B4G4R4A4_UNORM,true>(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_B4G4R4A4_UNORM,
+ DXGI_FORMAT_B4G4R4A4_UNORM,
+ DXGI_FORMAT_B4G4R4A4_UNORM,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_RGBA8:
+ {
+ if (AnyDevice(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R8G8B8A8_UNORM,
+ DXGI_FORMAT_R8G8B8A8_UNORM,
+ DXGI_FORMAT_R8G8B8A8_UNORM,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_RGBA8I:
+ {
+ if (AnyDevice(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R8G8B8A8_SINT,
+ DXGI_FORMAT_R8G8B8A8_SINT,
+ DXGI_FORMAT_R8G8B8A8_SINT,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_RGBA8UI:
+ {
+ if (AnyDevice(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R8G8B8A8_UINT,
+ DXGI_FORMAT_R8G8B8A8_UINT,
+ DXGI_FORMAT_R8G8B8A8_UINT,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_RGBA8_SNORM:
+ {
+ if (AnyDevice(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R8G8B8A8_SNORM,
+ DXGI_FORMAT_R8G8B8A8_SNORM,
+ DXGI_FORMAT_UNKNOWN,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_SRGB8:
+ {
+ if (AnyDevice(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R8G8B8A8_UNORM_SRGB,
+ DXGI_FORMAT_R8G8B8A8_UNORM_SRGB,
+ DXGI_FORMAT_UNKNOWN,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_SRGB8_ALPHA8:
+ {
+ if (AnyDevice(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R8G8B8A8_UNORM_SRGB,
+ DXGI_FORMAT_R8G8B8A8_UNORM_SRGB,
+ DXGI_FORMAT_R8G8B8A8_UNORM_SRGB,
+ DXGI_FORMAT_UNKNOWN);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case GL_STENCIL_INDEX8:
+ {
+ if (OnlyFL9_3(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_D24_UNORM_S8_UINT,
+ DXGI_FORMAT_UNKNOWN,
+ DXGI_FORMAT_UNKNOWN,
+ DXGI_FORMAT_D24_UNORM_S8_UINT);
+ return textureFormat;
+ }
+ else if (OnlyFL10Plus(renderer11DeviceCaps))
+ {
+ static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat,
+ DXGI_FORMAT_R24G8_TYPELESS,
+ DXGI_FORMAT_X24_TYPELESS_G8_UINT,
+ DXGI_FORMAT_UNKNOWN,
+ DXGI_FORMAT_D24_UNORM_S8_UINT);
+ return textureFormat;
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ default:
+ break;
+ }
+ // clang-format on
+
+ static const TextureFormat defaultInfo;
+ return defaultInfo;
+} // GetTextureFormatInfo
+
+} // namespace d3d11
+
+} // namespace rx
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/win32/NativeWindow.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/win32/NativeWindow.cpp
index 696dfd72f8..da6460b136 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/win32/NativeWindow.cpp
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/win32/NativeWindow.cpp
@@ -7,19 +7,42 @@
// NativeWindow.cpp: Handler for managing HWND native window types.
#include "libANGLE/renderer/d3d/d3d11/NativeWindow.h"
+#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h"
#include "common/debug.h"
+#include <initguid.h>
+#if !defined(__MINGW32__)
+#include <dcomp.h>
+#endif
+
namespace rx
{
-NativeWindow::NativeWindow(EGLNativeWindowType window) : mWindow(window)
+NativeWindow::NativeWindow(EGLNativeWindowType window,
+ const egl::Config *config,
+ bool directComposition)
+ : mWindow(window),
+ mDirectComposition(directComposition),
+ mDevice(nullptr),
+ mCompositionTarget(nullptr),
+ mVisual(nullptr),
+ mConfig(config)
{
}
+NativeWindow::~NativeWindow()
+{
+#if !defined(__MINGW32__)
+ SafeRelease(mCompositionTarget);
+ SafeRelease(mDevice);
+ SafeRelease(mVisual);
+#endif
+}
+
bool NativeWindow::initialize()
-{
- return true;
+{
+ return true;
}
bool NativeWindow::getClientRect(LPRECT rect)
@@ -47,7 +70,117 @@ HRESULT NativeWindow::createSwapChain(ID3D11Device* device, DXGIFactory* factory
return E_INVALIDARG;
}
- DXGI_SWAP_CHAIN_DESC swapChainDesc = { 0 };
+#if !defined(__MINGW32__)
+ if (mDirectComposition)
+ {
+ HMODULE dcomp = ::GetModuleHandle(TEXT("dcomp.dll"));
+ if (!dcomp)
+ {
+ return E_INVALIDARG;
+ }
+
+ typedef HRESULT(WINAPI * PFN_DCOMPOSITION_CREATE_DEVICE)(
+ IDXGIDevice * dxgiDevice, REFIID iid, void **dcompositionDevice);
+ PFN_DCOMPOSITION_CREATE_DEVICE createDComp =
+ reinterpret_cast<PFN_DCOMPOSITION_CREATE_DEVICE>(
+ GetProcAddress(dcomp, "DCompositionCreateDevice"));
+ if (!createDComp)
+ {
+ return E_INVALIDARG;
+ }
+
+ if (!mDevice)
+ {
+ IDXGIDevice *dxgiDevice = d3d11::DynamicCastComObject<IDXGIDevice>(device);
+ HRESULT result = createDComp(dxgiDevice, __uuidof(IDCompositionDevice),
+ reinterpret_cast<void **>(&mDevice));
+ SafeRelease(dxgiDevice);
+
+ if (FAILED(result))
+ {
+ return result;
+ }
+ }
+
+ if (!mCompositionTarget)
+ {
+ HRESULT result = mDevice->CreateTargetForHwnd(mWindow, TRUE, &mCompositionTarget);
+ if (FAILED(result))
+ {
+ return result;
+ }
+ }
+
+ if (!mVisual)
+ {
+ HRESULT result = mDevice->CreateVisual(&mVisual);
+ if (FAILED(result))
+ {
+ return result;
+ }
+ }
+
+ IDXGIFactory2 *factory2 = d3d11::DynamicCastComObject<IDXGIFactory2>(factory);
+ DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {0};
+ swapChainDesc.Width = width;
+ swapChainDesc.Height = height;
+ swapChainDesc.Format = format;
+ swapChainDesc.Stereo = FALSE;
+ swapChainDesc.SampleDesc.Count = 1;
+ swapChainDesc.SampleDesc.Quality = 0;
+ swapChainDesc.BufferUsage =
+ DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_BACK_BUFFER | DXGI_USAGE_SHADER_INPUT;
+ swapChainDesc.BufferCount = 2;
+ swapChainDesc.Scaling = DXGI_SCALING_STRETCH;
+ swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
+ swapChainDesc.AlphaMode =
+ mConfig->alphaSize == 0 ? DXGI_ALPHA_MODE_IGNORE : DXGI_ALPHA_MODE_PREMULTIPLIED;
+ swapChainDesc.Flags = 0;
+ IDXGISwapChain1 *swapChain1 = nullptr;
+ HRESULT result =
+ factory2->CreateSwapChainForComposition(device, &swapChainDesc, nullptr, &swapChain1);
+ if (SUCCEEDED(result))
+ {
+ *swapChain = static_cast<DXGISwapChain *>(swapChain1);
+ }
+ mVisual->SetContent(swapChain1);
+ mCompositionTarget->SetRoot(mVisual);
+ SafeRelease(factory2);
+ return result;
+ }
+
+ // Use IDXGIFactory2::CreateSwapChainForHwnd if DXGI 1.2 is available to create a DXGI_SWAP_EFFECT_SEQUENTIAL swap chain.
+ IDXGIFactory2 *factory2 = d3d11::DynamicCastComObject<IDXGIFactory2>(factory);
+ if (factory2 != nullptr)
+ {
+ DXGI_SWAP_CHAIN_DESC1 swapChainDesc = { 0 };
+ swapChainDesc.Width = width;
+ swapChainDesc.Height = height;
+ swapChainDesc.Format = format;
+ swapChainDesc.Stereo = FALSE;
+ swapChainDesc.SampleDesc.Count = 1;
+ swapChainDesc.SampleDesc.Quality = 0;
+ swapChainDesc.BufferUsage =
+ DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_SHADER_INPUT | DXGI_USAGE_BACK_BUFFER;
+ swapChainDesc.BufferCount = 1;
+ swapChainDesc.Scaling = DXGI_SCALING_STRETCH;
+ swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_SEQUENTIAL;
+ swapChainDesc.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED;
+ swapChainDesc.Flags = 0;
+ IDXGISwapChain1 *swapChain1 = nullptr;
+ HRESULT result = factory2->CreateSwapChainForHwnd(device, mWindow, &swapChainDesc, nullptr, nullptr, &swapChain1);
+ if (SUCCEEDED(result))
+ {
+ const HRESULT makeWindowAssociationResult = factory->MakeWindowAssociation(mWindow, DXGI_MWA_NO_ALT_ENTER);
+ UNUSED_VARIABLE(makeWindowAssociationResult);
+ *swapChain = static_cast<DXGISwapChain*>(swapChain1);
+ }
+ SafeRelease(factory2);
+ return result;
+ }
+#endif // !__MINGW32__
+
+ DXGI_SWAP_CHAIN_DESC swapChainDesc = {};
swapChainDesc.BufferCount = 1;
swapChainDesc.BufferDesc.Format = format;
swapChainDesc.BufferDesc.Width = width;
@@ -56,7 +189,8 @@ HRESULT NativeWindow::createSwapChain(ID3D11Device* device, DXGIFactory* factory
swapChainDesc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
swapChainDesc.BufferDesc.RefreshRate.Numerator = 0;
swapChainDesc.BufferDesc.RefreshRate.Denominator = 1;
- swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_BACK_BUFFER;
+ swapChainDesc.BufferUsage =
+ DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_SHADER_INPUT | DXGI_USAGE_BACK_BUFFER;
swapChainDesc.Flags = 0;
swapChainDesc.OutputWindow = mWindow;
swapChainDesc.SampleDesc.Count = 1;
@@ -68,9 +202,19 @@ HRESULT NativeWindow::createSwapChain(ID3D11Device* device, DXGIFactory* factory
if (SUCCEEDED(result))
{
const HRESULT makeWindowAssociationResult = factory->MakeWindowAssociation(mWindow, DXGI_MWA_NO_ALT_ENTER);
- UNUSED_TRACE_VARIABLE(makeWindowAssociationResult);
+ UNUSED_VARIABLE(makeWindowAssociationResult);
}
return result;
}
#endif
+
+void NativeWindow::commitChange()
+{
+#if !defined(__MINGW32__)
+ if (mDevice)
+ {
+ mDevice->Commit();
+ }
+#endif
+}
}
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.cpp
index f45a077d97..f401db614b 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.cpp
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.cpp
@@ -23,7 +23,6 @@ bool CoreWindowNativeWindow::initialize(EGLNativeWindowType window, IPropertySet
ComPtr<IPropertySet> props = propertySet;
ComPtr<IInspectable> win = window;
SIZE swapChainSize = {};
- bool swapChainSizeSpecified = false;
HRESULT result = S_OK;
// IPropertySet is an optional parameter and can be null.
@@ -32,12 +31,40 @@ bool CoreWindowNativeWindow::initialize(EGLNativeWindowType window, IPropertySet
if (propertySet)
{
result = props.As(&mPropertyMap);
- if (SUCCEEDED(result))
+ if (FAILED(result))
+ {
+ return false;
+ }
+
+ // The EGLRenderSurfaceSizeProperty is optional and may be missing. The IPropertySet
+ // was prevalidated to contain the EGLNativeWindowType before being passed to
+ // this host.
+ result = GetOptionalSizePropertyValue(mPropertyMap, EGLRenderSurfaceSizeProperty, &swapChainSize, &mSwapChainSizeSpecified);
+ if (FAILED(result))
+ {
+ return false;
+ }
+
+ // The EGLRenderResolutionScaleProperty is optional and may be missing. The IPropertySet
+ // was prevalidated to contain the EGLNativeWindowType before being passed to
+ // this host.
+ result = GetOptionalSinglePropertyValue(mPropertyMap, EGLRenderResolutionScaleProperty, &mSwapChainScale, &mSwapChainScaleSpecified);
+ if (FAILED(result))
+ {
+ return false;
+ }
+
+ if (!mSwapChainScaleSpecified)
{
- // The EGLRenderSurfaceSizeProperty is optional and may be missing. The IPropertySet
- // was prevalidated to contain the EGLNativeWindowType before being passed to
- // this host.
- result = GetOptionalSizePropertyValue(mPropertyMap, EGLRenderSurfaceSizeProperty, &swapChainSize, &swapChainSizeSpecified);
+ // Default value for the scale is 1.0f
+ mSwapChainScale = 1.0f;
+ }
+
+ // A EGLRenderSurfaceSizeProperty and a EGLRenderResolutionScaleProperty can't both be specified
+ if (mSwapChainScaleSpecified && mSwapChainSizeSpecified)
+ {
+ ERR("It is invalid to specify both an EGLRenderSurfaceSizeProperty and a EGLRenderResolutionScaleProperty.");
+ return false;
}
}
@@ -54,14 +81,19 @@ bool CoreWindowNativeWindow::initialize(EGLNativeWindowType window, IPropertySet
// of the host.
// Scaling of the swapchain output occurs automatically because if
// the scaling mode setting DXGI_SCALING_STRETCH on the swapchain.
- if (swapChainSizeSpecified)
+ if (mSwapChainSizeSpecified)
{
mClientRect = { 0, 0, swapChainSize.cx, swapChainSize.cy };
- mSupportsSwapChainResize = false;
}
else
{
- result = GetCoreWindowSizeInPixels(mCoreWindow, &mClientRect);
+ SIZE coreWindowSize;
+ result = GetCoreWindowSizeInPixels(mCoreWindow, &coreWindowSize);
+
+ if (SUCCEEDED(result))
+ {
+ mClientRect = { 0, 0, static_cast<long>(coreWindowSize.cx * mSwapChainScale), static_cast<long>(coreWindowSize.cy * mSwapChainScale) };
+ }
}
}
@@ -118,17 +150,25 @@ void CoreWindowNativeWindow::unregisterForSizeChangeEvents()
{
(void)mCoreWindow->remove_SizeChanged(mSizeChangedEventToken);
}
+
#if defined(ANGLE_ENABLE_WINDOWS_STORE) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP)
if (mDisplayInformation)
{
(void)mDisplayInformation->remove_OrientationChanged(mOrientationChangedEventToken);
}
#endif
+
mSizeChangedEventToken.value = 0;
mOrientationChangedEventToken.value = 0;
}
-HRESULT CoreWindowNativeWindow::createSwapChain(ID3D11Device *device, DXGIFactory *factory, DXGI_FORMAT format, unsigned int width, unsigned int height, DXGISwapChain **swapChain)
+HRESULT CoreWindowNativeWindow::createSwapChain(ID3D11Device *device,
+ DXGIFactory *factory,
+ DXGI_FORMAT format,
+ unsigned int width,
+ unsigned int height,
+ bool containsAlpha,
+ DXGISwapChain **swapChain)
{
if (device == NULL || factory == NULL || swapChain == NULL || width == 0 || height == 0)
{
@@ -142,10 +182,12 @@ HRESULT CoreWindowNativeWindow::createSwapChain(ID3D11Device *device, DXGIFactor
swapChainDesc.Stereo = FALSE;
swapChainDesc.SampleDesc.Count = 1;
swapChainDesc.SampleDesc.Quality = 0;
- swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_BACK_BUFFER;
+ swapChainDesc.BufferUsage =
+ DXGI_USAGE_SHADER_INPUT | DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_BACK_BUFFER;
swapChainDesc.BufferCount = 2;
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
swapChainDesc.Scaling = DXGI_SCALING_STRETCH;
+ swapChainDesc.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED;
*swapChain = nullptr;
@@ -180,13 +222,20 @@ HRESULT CoreWindowNativeWindow::createSwapChain(ID3D11Device *device, DXGIFactor
return result;
}
-HRESULT GetCoreWindowSizeInPixels(const ComPtr<ABI::Windows::UI::Core::ICoreWindow>& coreWindow, RECT *windowSize)
+inline HRESULT CoreWindowNativeWindow::scaleSwapChain(const Size &windowSize, const RECT &clientRect)
+{
+ // We don't need to do any additional work to scale CoreWindow swapchains.
+ // Using DXGI_SCALING_STRETCH to create the swapchain above does all the necessary work.
+ return S_OK;
+}
+
+HRESULT GetCoreWindowSizeInPixels(const ComPtr<ABI::Windows::UI::Core::ICoreWindow>& coreWindow, SIZE *windowSize)
{
ABI::Windows::Foundation::Rect bounds;
HRESULT result = coreWindow->get_Bounds(&bounds);
if (SUCCEEDED(result))
{
- *windowSize = { 0, 0, ConvertDipsToPixels(bounds.Width), ConvertDipsToPixels(bounds.Height) };
+ *windowSize = { ConvertDipsToPixels(bounds.Width), ConvertDipsToPixels(bounds.Height) };
}
return result;
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.h
index 87cdfe6f22..fc1cd124a1 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.h
@@ -19,16 +19,25 @@ typedef ABI::Windows::Foundation::__FITypedEventHandler_2_Windows__CGraphics__CD
namespace rx
{
-
class CoreWindowNativeWindow : public InspectableNativeWindow, public std::enable_shared_from_this<CoreWindowNativeWindow>
{
public:
~CoreWindowNativeWindow();
- bool initialize(EGLNativeWindowType window, IPropertySet *propertySet);
+ bool initialize(EGLNativeWindowType window, IPropertySet *propertySet) override;
+ HRESULT createSwapChain(ID3D11Device *device,
+ DXGIFactory *factory,
+ DXGI_FORMAT format,
+ unsigned int width,
+ unsigned int height,
+ bool containsAlpha,
+ DXGISwapChain **swapChain) override;
+
+ protected:
+ HRESULT scaleSwapChain(const Size &windowSize, const RECT &clientRect) override;
+
bool registerForSizeChangeEvents();
void unregisterForSizeChangeEvents();
- HRESULT createSwapChain(ID3D11Device *device, DXGIFactory *factory, DXGI_FORMAT format, unsigned int width, unsigned int height, DXGISwapChain **swapChain);
private:
ComPtr<ABI::Windows::UI::Core::ICoreWindow> mCoreWindow;
@@ -70,39 +79,40 @@ class CoreWindowSizeChangedHandler :
return S_OK;
}
- IFACEMETHOD(Invoke)(ABI::Windows::Graphics::Display::IDisplayInformation *displayInformation, IInspectable *)
- {
-#if defined(ANGLE_ENABLE_WINDOWS_STORE) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP)
- NativeWindow::RotationFlags flags = NativeWindow::RotateNone;
- ABI::Windows::Graphics::Display::DisplayOrientations orientation;
- if (SUCCEEDED(displayInformation->get_CurrentOrientation(&orientation)))
+ IFACEMETHOD(Invoke)(ABI::Windows::Graphics::Display::IDisplayInformation *displayInformation, IInspectable *)
{
- switch (orientation)
+ #if defined(ANGLE_ENABLE_WINDOWS_STORE) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP)
+ NativeWindow::RotationFlags flags = NativeWindow::RotateNone;
+ ABI::Windows::Graphics::Display::DisplayOrientations orientation;
+ if (SUCCEEDED(displayInformation->get_CurrentOrientation(&orientation)))
{
- case ABI::Windows::Graphics::Display::DisplayOrientations_Landscape:
- flags = NativeWindow::RotateLeft;
- break;
- case ABI::Windows::Graphics::Display::DisplayOrientations_LandscapeFlipped:
- flags = NativeWindow::RotateRight;
- break;
- default:
- break;
+ switch (orientation)
+ {
+ case ABI::Windows::Graphics::Display::DisplayOrientations_Landscape:
+ flags = NativeWindow::RotateLeft;
+ break;
+ case ABI::Windows::Graphics::Display::DisplayOrientations_LandscapeFlipped:
+ flags = NativeWindow::RotateRight;
+ break;
+ default:
+ break;
+ }
}
+ std::shared_ptr<InspectableNativeWindow> host = mHost.lock();
+ if (host)
+ {
+ host->setRotationFlags(flags);
+ }
+ #endif
+ return S_OK;
}
- std::shared_ptr<InspectableNativeWindow> host = mHost.lock();
- if (host)
- {
- host->setRotationFlags(flags);
- }
-#endif
- return S_OK;
- }
+
private:
std::weak_ptr<InspectableNativeWindow> mHost;
};
-HRESULT GetCoreWindowSizeInPixels(const ComPtr<ABI::Windows::UI::Core::ICoreWindow>& coreWindow, RECT *windowSize);
+HRESULT GetCoreWindowSizeInPixels(const ComPtr<ABI::Windows::UI::Core::ICoreWindow>& coreWindow, SIZE *windowSize);
}
#endif // LIBANGLE_RENDERER_D3D_D3D11_WINRT_COREWINDOWNATIVEWINDOW_H_
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.cpp
index e83f47929f..aacfadd2f0 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.cpp
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.cpp
@@ -11,9 +11,20 @@
namespace rx
{
-NativeWindow::NativeWindow(EGLNativeWindowType window)
+NativeWindow::NativeWindow(EGLNativeWindowType window,
+ const egl::Config *config,
+ bool directComposition)
{
mWindow = window;
+ mConfig = config;
+}
+
+NativeWindow::~NativeWindow()
+{
+}
+
+void NativeWindow::commitChange()
+{
}
bool NativeWindow::initialize()
@@ -95,7 +106,9 @@ HRESULT NativeWindow::createSwapChain(ID3D11Device *device, DXGIFactory *factory
{
if (mImpl)
{
- return mImpl->createSwapChain(device, factory, format, width, height, swapChain);
+ bool containsAlpha = (mConfig->alphaSize > 0);
+ return mImpl->createSwapChain(device, factory, format, width, height, containsAlpha,
+ swapChain);
}
return E_UNEXPECTED;
@@ -209,16 +222,47 @@ bool IsEGLConfiguredPropertySet(EGLNativeWindowType window, ABI::Windows::Founda
// A Valid EGLNativeWindowType IInspectable can only be:
//
// ICoreWindow
+// ISwapChainPanel
// IPropertySet
-//
+//
// Anything else will be rejected as an invalid IInspectable.
bool IsValidEGLNativeWindowType(EGLNativeWindowType window)
{
return IsCoreWindow(window) || IsSwapChainPanel(window) || IsEGLConfiguredPropertySet(window);
}
+// Retrieve an optional property from a property set
+HRESULT GetOptionalPropertyValue(const ComPtr<ABI::Windows::Foundation::Collections::IMap<HSTRING, IInspectable*>> &propertyMap,
+ const wchar_t *propertyName,
+ boolean *hasKey,
+ ComPtr<ABI::Windows::Foundation::IPropertyValue> &propertyValue)
+{
+ if (!propertyMap || !hasKey)
+ {
+ return E_INVALIDARG;
+ }
+
+ // Assume that the value does not exist
+ *hasKey = false;
+
+ HRESULT result = propertyMap->HasKey(HStringReference(propertyName).Get(), hasKey);
+ if (SUCCEEDED(result) && !(*hasKey))
+ {
+ // Value does not exist, so return S_OK and set the exists parameter to false to indicate
+ // that a the optional property does not exist.
+ return S_OK;
+ }
+
+ if (SUCCEEDED(result))
+ {
+ result = propertyMap->Lookup(HStringReference(propertyName).Get(), &propertyValue);
+ }
+
+ return result;
+}
+
// Attempts to read an optional SIZE property value that is assumed to be in the form of
-// an ABI::Windows::Foundation::Size. This function validates the Size value before returning
+// an ABI::Windows::Foundation::Size. This function validates the Size value before returning
// it to the caller.
//
// Possible return values are:
@@ -229,62 +273,110 @@ bool IsValidEGLNativeWindowType(EGLNativeWindowType window)
// * Invalid property value (width/height must be > 0)
// Additional errors may be returned from IMap or IPropertyValue
//
-HRESULT GetOptionalSizePropertyValue(const ComPtr<ABI::Windows::Foundation::Collections::IMap<HSTRING, IInspectable*>>& propertyMap, const wchar_t *propertyName, SIZE *value, bool *valueExists)
+HRESULT GetOptionalSizePropertyValue(const ComPtr<ABI::Windows::Foundation::Collections::IMap<HSTRING, IInspectable*>> &propertyMap,
+ const wchar_t *propertyName, SIZE *value, bool *valueExists)
{
- if (!propertyMap || !propertyName || !value || !valueExists)
+ ComPtr<ABI::Windows::Foundation::IPropertyValue> propertyValue;
+ ABI::Windows::Foundation::PropertyType propertyType = ABI::Windows::Foundation::PropertyType::PropertyType_Empty;
+ Size sizeValue = { 0, 0 };
+ boolean hasKey = false;
+
+ if (!propertyMap || !value || !valueExists)
{
- return false;
+ return E_INVALIDARG;
}
// Assume that the value does not exist
*valueExists = false;
*value = { 0, 0 };
+ HRESULT result = GetOptionalPropertyValue(propertyMap, propertyName, &hasKey, propertyValue);
+ if (SUCCEEDED(result) && hasKey)
+ {
+ result = propertyValue->get_Type(&propertyType);
+
+ // Check if the expected Size property is of PropertyType_Size type.
+ if (SUCCEEDED(result) && propertyType == ABI::Windows::Foundation::PropertyType::PropertyType_Size)
+ {
+ if (SUCCEEDED(propertyValue->GetSize(&sizeValue)) && (sizeValue.Width > 0 && sizeValue.Height > 0))
+ {
+ // A valid property value exists
+ *value = { static_cast<long>(sizeValue.Width), static_cast<long>(sizeValue.Height) };
+ *valueExists = true;
+ result = S_OK;
+ }
+ else
+ {
+ // An invalid Size property was detected. Width/Height values must > 0
+ result = E_INVALIDARG;
+ }
+ }
+ else
+ {
+ // An invalid property type was detected. Size property must be of PropertyType_Size
+ result = E_INVALIDARG;
+ }
+ }
+
+ return result;
+}
+
+// Attempts to read an optional float property value that is assumed to be in the form of
+// an ABI::Windows::Foundation::Single. This function validates the Single value before returning
+// it to the caller.
+//
+// Possible return values are:
+// S_OK, valueExists == true - optional Single value was successfully retrieved and validated
+// S_OK, valueExists == false - optional Single value was not found
+// E_INVALIDARG, valueExists = false - optional Single value was malformed in the property set.
+// * Incorrect property type ( must be PropertyType_Single)
+// * Invalid property value (must be > 0)
+// Additional errors may be returned from IMap or IPropertyValue
+//
+HRESULT GetOptionalSinglePropertyValue(const ComPtr<ABI::Windows::Foundation::Collections::IMap<HSTRING, IInspectable*>> &propertyMap,
+ const wchar_t *propertyName, float *value, bool *valueExists)
+{
ComPtr<ABI::Windows::Foundation::IPropertyValue> propertyValue;
ABI::Windows::Foundation::PropertyType propertyType = ABI::Windows::Foundation::PropertyType::PropertyType_Empty;
- Size sizeValue = { 0, 0 };
+ float scaleValue = 0.0f;
boolean hasKey = false;
- HRESULT result = propertyMap->HasKey(HStringReference(propertyName).Get(), &hasKey);
- if (SUCCEEDED(result) && !hasKey)
+ if (!propertyMap || !value || !valueExists)
{
- // Value does not exist, so return S_OK and set the exists parameter to false to indicate
- // that a the optional property does not exist.
- *valueExists = false;
- return S_OK;
+ return E_INVALIDARG;
}
- if (SUCCEEDED(result))
- {
- result = propertyMap->Lookup(HStringReference(propertyName).Get(), &propertyValue);
- }
+ // Assume that the value does not exist
+ *valueExists = false;
+ *value = 0.0f;
- if (SUCCEEDED(result))
+ HRESULT result = GetOptionalPropertyValue(propertyMap, propertyName, &hasKey, propertyValue);
+ if (SUCCEEDED(result) && hasKey)
{
result = propertyValue->get_Type(&propertyType);
- }
- // Check if the expected Size property is of PropertyType_Size type.
- if (SUCCEEDED(result) && propertyType == ABI::Windows::Foundation::PropertyType::PropertyType_Size)
- {
- if (SUCCEEDED(propertyValue->GetSize(&sizeValue)) && (sizeValue.Width > 0 && sizeValue.Height > 0))
+ // Check if the expected Scale property is of PropertyType_Single type.
+ if (SUCCEEDED(result) && propertyType == ABI::Windows::Foundation::PropertyType::PropertyType_Single)
{
- // A valid property value exists
- *value = { static_cast<long>(sizeValue.Width), static_cast<long>(sizeValue.Height) };
- *valueExists = true;
- result = S_OK;
+ if (SUCCEEDED(propertyValue->GetSingle(&scaleValue)) && (scaleValue > 0.0f))
+ {
+ // A valid property value exists
+ *value = scaleValue;
+ *valueExists = true;
+ result = S_OK;
+ }
+ else
+ {
+ // An invalid scale was set
+ result = E_INVALIDARG;
+ }
}
else
{
- // An invalid Size property was detected. Width/Height values must > 0
+ // An invalid property type was detected. Size property must be of PropertyType_Single
result = E_INVALIDARG;
}
}
- else
- {
- // An invalid property type was detected. Size property must be of PropertyType_Size
- result = E_INVALIDARG;
- }
return result;
}
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.h
index f0534077ae..2d58f1c00a 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.h
@@ -33,7 +33,9 @@ class InspectableNativeWindow
public:
InspectableNativeWindow() :
mSupportsSwapChainResize(true),
- mRequiresSwapChainScaling(false),
+ mSwapChainSizeSpecified(false),
+ mSwapChainScaleSpecified(false),
+ mSwapChainScale(1.0f),
mClientRectChanged(false),
mClientRect({0,0,0,0}),
mNewClientRect({0,0,0,0}),
@@ -44,14 +46,17 @@ class InspectableNativeWindow
virtual ~InspectableNativeWindow(){}
virtual bool initialize(EGLNativeWindowType window, IPropertySet *propertySet) = 0;
- virtual HRESULT createSwapChain(ID3D11Device *device, DXGIFactory *factory, DXGI_FORMAT format, unsigned int width, unsigned int height, DXGISwapChain **swapChain) = 0;
- virtual bool registerForSizeChangeEvents() = 0;
- virtual void unregisterForSizeChangeEvents() = 0;
- virtual HRESULT scaleSwapChain(const Size& newSize) { return S_OK; }
+ virtual HRESULT createSwapChain(ID3D11Device *device,
+ DXGIFactory *factory,
+ DXGI_FORMAT format,
+ unsigned int width,
+ unsigned int height,
+ bool containsAlpha,
+ DXGISwapChain **swapChain) = 0;
bool getClientRect(RECT *rect)
{
- if (mClientRectChanged && mSupportsSwapChainResize)
+ if (mClientRectChanged)
{
mClientRect = mNewClientRect;
}
@@ -61,17 +66,34 @@ class InspectableNativeWindow
return true;
}
- void setNewClientSize(const Size &newSize)
+ // setNewClientSize is used by the WinRT size change handler. It isn't used by the rest of ANGLE.
+ void setNewClientSize(const Size &newWindowSize)
{
- if (mSupportsSwapChainResize)
- {
- mNewClientRect = { 0, 0, ConvertDipsToPixels(newSize.Width), ConvertDipsToPixels(newSize.Height) };
- mClientRectChanged = true;
- }
+ // If the client doesn't support swapchain resizing then we should have already unregistered from size change handler
+ ASSERT(mSupportsSwapChainResize);
- if (mRequiresSwapChainScaling)
+ if (mSupportsSwapChainResize)
{
- scaleSwapChain(newSize);
+ // If the swapchain size was specified then we should ignore this call too
+ if (!mSwapChainSizeSpecified)
+ {
+ // We don't have to check if a swapchain scale was specified here; the default value is 1.0f which will have no effect.
+ mNewClientRect = { 0, 0, ConvertDipsToPixels(newWindowSize.Width), ConvertDipsToPixels(newWindowSize.Height) };
+ mClientRectChanged = true;
+
+ // If a scale was specified, then now is the time to apply the scale matrix for the new swapchain size and window size
+ if (mSwapChainScaleSpecified)
+ {
+ scaleSwapChain(newWindowSize, mNewClientRect);
+ }
+ }
+
+ // Even if the swapchain size was fixed, the window might have changed size.
+ // In this case, we should recalculate the scale matrix to account for the new window size
+ if (mSwapChainSizeSpecified)
+ {
+ scaleSwapChain(newWindowSize, mClientRect);
+ }
}
}
@@ -85,9 +107,13 @@ class InspectableNativeWindow
mRotationFlags = flags;
}
-protected:
- bool mSupportsSwapChainResize;
- bool mRequiresSwapChainScaling;
+ protected:
+ virtual HRESULT scaleSwapChain(const Size &windowSize, const RECT &clientRect) = 0;
+
+ bool mSupportsSwapChainResize; // Support for IDXGISwapChain::ResizeBuffers method
+ bool mSwapChainSizeSpecified; // If an EGLRenderSurfaceSizeProperty was specified
+ bool mSwapChainScaleSpecified; // If an EGLRenderResolutionScaleProperty was specified
+ float mSwapChainScale; // The scale value specified by the EGLRenderResolutionScaleProperty property
RECT mClientRect;
RECT mNewClientRect;
bool mClientRectChanged;
@@ -100,8 +126,17 @@ bool IsValidEGLNativeWindowType(EGLNativeWindowType window);
bool IsCoreWindow(EGLNativeWindowType window, ComPtr<ABI::Windows::UI::Core::ICoreWindow> *coreWindow = nullptr);
bool IsSwapChainPanel(EGLNativeWindowType window, ComPtr<ABI::Windows::UI::Xaml::Controls::ISwapChainPanel> *swapChainPanel = nullptr);
bool IsEGLConfiguredPropertySet(EGLNativeWindowType window, ABI::Windows::Foundation::Collections::IPropertySet **propertySet = nullptr, IInspectable **inspectable = nullptr);
-HRESULT GetOptionalSizePropertyValue(const ComPtr<ABI::Windows::Foundation::Collections::IMap<HSTRING, IInspectable*>>& propertyMap, const wchar_t *propertyName, SIZE *value, bool *valueExists);
+HRESULT GetOptionalPropertyValue(const ComPtr<ABI::Windows::Foundation::Collections::IMap<HSTRING, IInspectable*>> &propertyMap,
+ const wchar_t *propertyName,
+ boolean *hasKey,
+ ComPtr<ABI::Windows::Foundation::IPropertyValue> &propertyValue);
+
+HRESULT GetOptionalSizePropertyValue(const ComPtr<ABI::Windows::Foundation::Collections::IMap<HSTRING, IInspectable*>> &propertyMap,
+ const wchar_t *propertyName, SIZE *value, bool *valueExists);
+
+HRESULT GetOptionalSinglePropertyValue(const ComPtr<ABI::Windows::Foundation::Collections::IMap<HSTRING, IInspectable*>> &propertyMap,
+ const wchar_t *propertyName, float *value, bool *valueExists);
}
#endif // LIBANGLE_RENDERER_D3D_D3D11_WINRT_INSPECTABLENATIVEWINDOW_H_
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow.cpp
index 0b48b54334..d3ed35b3c6 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow.cpp
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow.cpp
@@ -11,7 +11,11 @@
#include <algorithm>
#include <math.h>
+using namespace ABI::Windows::Foundation;
using namespace ABI::Windows::Foundation::Collections;
+using namespace ABI::Windows::UI::Core;
+using namespace ABI::Windows::UI::Xaml;
+using namespace Microsoft::WRL;
namespace rx
{
@@ -20,12 +24,74 @@ SwapChainPanelNativeWindow::~SwapChainPanelNativeWindow()
unregisterForSizeChangeEvents();
}
+template <typename T>
+struct AddFtmBase
+{
+ typedef Implements<RuntimeClassFlags<ClassicCom>, T, FtmBase> Type;
+};
+
+template <typename CODE>
+HRESULT RunOnUIThread(CODE &&code, const ComPtr<ICoreDispatcher> &dispatcher)
+{
+ ComPtr<IAsyncAction> asyncAction;
+ HRESULT result = S_OK;
+
+ boolean hasThreadAccess;
+ result = dispatcher->get_HasThreadAccess(&hasThreadAccess);
+ if (FAILED(result))
+ {
+ return result;
+ }
+
+ if (hasThreadAccess)
+ {
+ return code();
+ }
+ else
+ {
+ Event waitEvent(CreateEventEx(NULL, NULL, CREATE_EVENT_MANUAL_RESET, EVENT_ALL_ACCESS));
+ if (!waitEvent.IsValid())
+ {
+ return E_FAIL;
+ }
+
+ HRESULT codeResult = E_FAIL;
+ auto handler =
+ Callback<AddFtmBase<IDispatchedHandler>::Type>([&codeResult, &code, &waitEvent]
+ {
+ codeResult = code();
+ SetEvent(waitEvent.Get());
+ return S_OK;
+ });
+
+ result = dispatcher->RunAsync(CoreDispatcherPriority_Normal, handler.Get(),
+ asyncAction.GetAddressOf());
+ if (FAILED(result))
+ {
+ return result;
+ }
+
+ auto waitResult = WaitForSingleObjectEx(waitEvent.Get(), 10 * 1000, true);
+ if (waitResult != WAIT_OBJECT_0)
+ {
+ // Wait 10 seconds before giving up. At this point, the application is in an
+ // unrecoverable state (probably deadlocked). We therefore terminate the application
+ // entirely. This also prevents stack corruption if the async operation is eventually
+ // run.
+ ERR("Timeout waiting for async action on UI thread. The UI thread might be blocked.");
+ std::terminate();
+ return E_FAIL;
+ }
+
+ return codeResult;
+ }
+}
+
bool SwapChainPanelNativeWindow::initialize(EGLNativeWindowType window, IPropertySet *propertySet)
{
ComPtr<IPropertySet> props = propertySet;
ComPtr<IInspectable> win = window;
SIZE swapChainSize = {};
- bool swapChainSizeSpecified = false;
HRESULT result = S_OK;
// IPropertySet is an optional parameter and can be null.
@@ -34,12 +100,40 @@ bool SwapChainPanelNativeWindow::initialize(EGLNativeWindowType window, IPropert
if (propertySet)
{
result = props.As(&mPropertyMap);
- if (SUCCEEDED(result))
+ if (FAILED(result))
+ {
+ return false;
+ }
+
+ // The EGLRenderSurfaceSizeProperty is optional and may be missing. The IPropertySet
+ // was prevalidated to contain the EGLNativeWindowType before being passed to
+ // this host.
+ result = GetOptionalSizePropertyValue(mPropertyMap, EGLRenderSurfaceSizeProperty, &swapChainSize, &mSwapChainSizeSpecified);
+ if (FAILED(result))
+ {
+ return false;
+ }
+
+ // The EGLRenderResolutionScaleProperty is optional and may be missing. The IPropertySet
+ // was prevalidated to contain the EGLNativeWindowType before being passed to
+ // this host.
+ result = GetOptionalSinglePropertyValue(mPropertyMap, EGLRenderResolutionScaleProperty, &mSwapChainScale, &mSwapChainScaleSpecified);
+ if (FAILED(result))
+ {
+ return false;
+ }
+
+ if (!mSwapChainScaleSpecified)
+ {
+ // Default value for the scale is 1.0f
+ mSwapChainScale = 1.0f;
+ }
+
+ // A EGLRenderSurfaceSizeProperty and a EGLRenderResolutionScaleProperty can't both be specified
+ if (mSwapChainScaleSpecified && mSwapChainSizeSpecified)
{
- // The EGLRenderSurfaceSizeProperty is optional and may be missing. The IPropertySet
- // was prevalidated to contain the EGLNativeWindowType before being passed to
- // this host.
- result = GetOptionalSizePropertyValue(mPropertyMap, EGLRenderSurfaceSizeProperty, &swapChainSize, &swapChainSizeSpecified);
+ ERR("It is invalid to specify both an EGLRenderSurfaceSizeProperty and a EGLRenderResolutionScaleProperty.");
+ return false;
}
}
@@ -48,6 +142,18 @@ bool SwapChainPanelNativeWindow::initialize(EGLNativeWindowType window, IPropert
result = win.As(&mSwapChainPanel);
}
+ ComPtr<IDependencyObject> swapChainPanelDependencyObject;
+ if (SUCCEEDED(result))
+ {
+ result = mSwapChainPanel.As(&swapChainPanelDependencyObject);
+ }
+
+ if (SUCCEEDED(result))
+ {
+ result = swapChainPanelDependencyObject->get_Dispatcher(
+ mSwapChainPanelDispatcher.GetAddressOf());
+ }
+
if (SUCCEEDED(result))
{
// If a swapchain size is specfied, then the automatic resize
@@ -57,16 +163,24 @@ bool SwapChainPanelNativeWindow::initialize(EGLNativeWindowType window, IPropert
// Scaling of the swapchain output needs to be handled by the
// host for swapchain panels even though the scaling mode setting
// DXGI_SCALING_STRETCH is configured on the swapchain.
- if (swapChainSizeSpecified)
+ if (mSwapChainSizeSpecified)
{
mClientRect = { 0, 0, swapChainSize.cx, swapChainSize.cy };
-
- // Enable host swapchain scaling
- mRequiresSwapChainScaling = true;
}
else
{
- result = GetSwapChainPanelSize(mSwapChainPanel, &mClientRect, &mRequiresSwapChainScaling);
+ SIZE swapChainPanelSize;
+ result = GetSwapChainPanelSize(mSwapChainPanel, mSwapChainPanelDispatcher,
+ &swapChainPanelSize, &mSwapChainScale);
+ if (mSwapChainScale != 1.0f)
+ mSwapChainScaleSpecified = true;
+
+ if (SUCCEEDED(result))
+ {
+ // Update the client rect to account for any swapchain scale factor
+ mClientRect = { 0, 0, static_cast<long>(ConvertDipsToPixels(swapChainPanelSize.cx * mSwapChainScale)),
+ static_cast<long>(ConvertDipsToPixels(swapChainPanelSize.cy * mSwapChainScale)) };
+ }
}
}
@@ -82,8 +196,8 @@ bool SwapChainPanelNativeWindow::initialize(EGLNativeWindowType window, IPropert
bool SwapChainPanelNativeWindow::registerForSizeChangeEvents()
{
- ComPtr<ABI::Windows::UI::Xaml::ISizeChangedEventHandler> sizeChangedHandler;
- ComPtr<ABI::Windows::UI::Xaml::IFrameworkElement> frameworkElement;
+ ComPtr<ISizeChangedEventHandler> sizeChangedHandler;
+ ComPtr<IFrameworkElement> frameworkElement;
HRESULT result = Microsoft::WRL::MakeAndInitialize<SwapChainPanelSizeChangedHandler>(sizeChangedHandler.ReleaseAndGetAddressOf(), this->shared_from_this());
if (SUCCEEDED(result))
@@ -93,7 +207,13 @@ bool SwapChainPanelNativeWindow::registerForSizeChangeEvents()
if (SUCCEEDED(result))
{
- result = frameworkElement->add_SizeChanged(sizeChangedHandler.Get(), &mSizeChangedEventToken);
+ result = RunOnUIThread(
+ [this, frameworkElement, sizeChangedHandler]
+ {
+ return frameworkElement->add_SizeChanged(sizeChangedHandler.Get(),
+ &mSizeChangedEventToken);
+ },
+ mSwapChainPanelDispatcher);
}
if (SUCCEEDED(result))
@@ -106,16 +226,27 @@ bool SwapChainPanelNativeWindow::registerForSizeChangeEvents()
void SwapChainPanelNativeWindow::unregisterForSizeChangeEvents()
{
- ComPtr<ABI::Windows::UI::Xaml::IFrameworkElement> frameworkElement;
- if (SUCCEEDED(mSwapChainPanel.As(&frameworkElement)))
+ ComPtr<IFrameworkElement> frameworkElement;
+ if (mSwapChainPanel && SUCCEEDED(mSwapChainPanel.As(&frameworkElement)))
{
- (void)frameworkElement->remove_SizeChanged(mSizeChangedEventToken);
+ RunOnUIThread(
+ [this, frameworkElement]
+ {
+ return frameworkElement->remove_SizeChanged(mSizeChangedEventToken);
+ },
+ mSwapChainPanelDispatcher);
}
mSizeChangedEventToken.value = 0;
}
-HRESULT SwapChainPanelNativeWindow::createSwapChain(ID3D11Device *device, DXGIFactory *factory, DXGI_FORMAT format, unsigned int width, unsigned int height, DXGISwapChain **swapChain)
+HRESULT SwapChainPanelNativeWindow::createSwapChain(ID3D11Device *device,
+ DXGIFactory *factory,
+ DXGI_FORMAT format,
+ unsigned int width,
+ unsigned int height,
+ bool containsAlpha,
+ DXGISwapChain **swapChain)
{
if (device == NULL || factory == NULL || swapChain == NULL || width == 0 || height == 0)
{
@@ -129,11 +260,13 @@ HRESULT SwapChainPanelNativeWindow::createSwapChain(ID3D11Device *device, DXGIFa
swapChainDesc.Stereo = FALSE;
swapChainDesc.SampleDesc.Count = 1;
swapChainDesc.SampleDesc.Quality = 0;
- swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_BACK_BUFFER;
+ swapChainDesc.BufferUsage =
+ DXGI_USAGE_SHADER_INPUT | DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_BACK_BUFFER;
swapChainDesc.BufferCount = 2;
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
swapChainDesc.Scaling = DXGI_SCALING_STRETCH;
- swapChainDesc.AlphaMode = DXGI_ALPHA_MODE_IGNORE;
+ swapChainDesc.AlphaMode =
+ containsAlpha ? DXGI_ALPHA_MODE_PREMULTIPLIED : DXGI_ALPHA_MODE_IGNORE;
*swapChain = nullptr;
@@ -149,7 +282,12 @@ HRESULT SwapChainPanelNativeWindow::createSwapChain(ID3D11Device *device, DXGIFa
if (SUCCEEDED(result))
{
- result = swapChainPanelNative->SetSwapChain(newSwapChain.Get());
+ result = RunOnUIThread(
+ [swapChainPanelNative, newSwapChain]
+ {
+ return swapChainPanelNative->SetSwapChain(newSwapChain.Get());
+ },
+ mSwapChainPanelDispatcher);
}
if (SUCCEEDED(result))
@@ -164,34 +302,28 @@ HRESULT SwapChainPanelNativeWindow::createSwapChain(ID3D11Device *device, DXGIFa
// If the host is responsible for scaling the output of the swapchain, then
// scale it now before returning an instance to the caller. This is done by
// first reading the current size of the swapchain panel, then scaling
- if (SUCCEEDED(result) && mRequiresSwapChainScaling)
- {
- ComPtr<ABI::Windows::UI::Xaml::IUIElement> uiElement;
- result = mSwapChainPanel.As(&uiElement);
- ASSERT(SUCCEEDED(result));
-
- Size currentSize;
- result = uiElement->get_RenderSize(&currentSize);
- ASSERT(SUCCEEDED(result));
- result = scaleSwapChain(currentSize);
- }
-
if (SUCCEEDED(result))
{
- // If automatic swapchain resize behaviors have been disabled, then
- // unregister for the resize change events.
- if (mSupportsSwapChainResize == false)
+ if (mSwapChainSizeSpecified || mSwapChainScaleSpecified)
{
- unregisterForSizeChangeEvents();
+ ComPtr<ABI::Windows::UI::Xaml::IUIElement> uiElement;
+ result = mSwapChainPanel.As(&uiElement);
+ ASSERT(SUCCEEDED(result));
+
+ Size currentSize;
+ result = uiElement->get_RenderSize(&currentSize);
+ ASSERT(SUCCEEDED(result));
+ result = scaleSwapChain(currentSize, mClientRect);
}
}
return result;
}
-HRESULT SwapChainPanelNativeWindow::scaleSwapChain(const Size &newSize)
+HRESULT SwapChainPanelNativeWindow::scaleSwapChain(const Size &windowSize, const RECT &clientRect)
{
- ABI::Windows::Foundation::Size renderScale = { newSize.Width / mNewClientRect.right, newSize.Height / mNewClientRect.bottom };
+ Size renderScale = {windowSize.Width / clientRect.right,
+ windowSize.Height / clientRect.bottom};
// Setup a scale matrix for the swap chain
DXGI_MATRIX_3X2_F scaleMatrix = {};
scaleMatrix._11 = renderScale.Width;
@@ -207,25 +339,33 @@ HRESULT SwapChainPanelNativeWindow::scaleSwapChain(const Size &newSize)
return result;
}
-HRESULT GetSwapChainPanelSize(const ComPtr<ABI::Windows::UI::Xaml::Controls::ISwapChainPanel> &swapChainPanel, RECT *windowSize, bool *scalingActive)
+HRESULT GetSwapChainPanelSize(
+ const ComPtr<ABI::Windows::UI::Xaml::Controls::ISwapChainPanel> &swapChainPanel,
+ const ComPtr<ICoreDispatcher> &dispatcher,
+ SIZE *windowSize, float *scaleFactor)
{
- ComPtr<ABI::Windows::UI::Xaml::IUIElement> uiElement;
- ABI::Windows::Foundation::Size renderSize = { 0, 0 };
+ ComPtr<IUIElement> uiElement;
+ Size renderSize = {0, 0};
HRESULT result = swapChainPanel.As(&uiElement);
if (SUCCEEDED(result))
{
- result = uiElement->get_RenderSize(&renderSize);
+ result = RunOnUIThread(
+ [uiElement, &renderSize]
+ {
+ return uiElement->get_RenderSize(&renderSize);
+ },
+ dispatcher);
}
if (SUCCEEDED(result))
{
long width = ConvertDipsToPixels(renderSize.Width);
long height = ConvertDipsToPixels(renderSize.Height);
- *windowSize = { 0, 0, width, height };
+ *windowSize = { width, height };
- if (scalingActive)
+ if (scaleFactor)
{
- *scalingActive = width != renderSize.Width || height != renderSize.Height;
+ *scaleFactor = renderSize.Width / width;
}
}
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow.h
index 5debd2fd0b..09d87ad523 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow.h
@@ -18,14 +18,24 @@ class SwapChainPanelNativeWindow : public InspectableNativeWindow, public std::e
public:
~SwapChainPanelNativeWindow();
- bool initialize(EGLNativeWindowType window, IPropertySet *propertySet);
+ bool initialize(EGLNativeWindowType window, IPropertySet *propertySet) override;
+ HRESULT createSwapChain(ID3D11Device *device,
+ DXGIFactory *factory,
+ DXGI_FORMAT format,
+ unsigned int width,
+ unsigned int height,
+ bool containsAlpha,
+ DXGISwapChain **swapChain) override;
+
+ protected:
+ HRESULT scaleSwapChain(const Size &windowSize, const RECT &clientRect) override;
+
bool registerForSizeChangeEvents();
void unregisterForSizeChangeEvents();
- HRESULT createSwapChain(ID3D11Device *device, DXGIFactory *factory, DXGI_FORMAT format, unsigned int width, unsigned int height, DXGISwapChain **swapChain);
- HRESULT scaleSwapChain(const Size &newSize) override;
private:
ComPtr<ABI::Windows::UI::Xaml::Controls::ISwapChainPanel> mSwapChainPanel;
+ ComPtr<ABI::Windows::UI::Core::ICoreDispatcher> mSwapChainPanelDispatcher;
ComPtr<IMap<HSTRING, IInspectable*>> mPropertyMap;
ComPtr<DXGISwapChain> mSwapChain;
};
@@ -73,6 +83,9 @@ class SwapChainPanelSizeChangedHandler :
std::weak_ptr<InspectableNativeWindow> mHost;
};
-HRESULT GetSwapChainPanelSize(const ComPtr<ABI::Windows::UI::Xaml::Controls::ISwapChainPanel> &swapChainPanel, RECT *windowSize, bool *scalingActive = nullptr);
+HRESULT GetSwapChainPanelSize(
+ const ComPtr<ABI::Windows::UI::Xaml::Controls::ISwapChainPanel> &swapChainPanel,
+ const ComPtr<ABI::Windows::UI::Core::ICoreDispatcher> &dispatcher,
+ SIZE *windowSize, float *scaleFactor);
}
#endif // LIBANGLE_RENDERER_D3D_D3D11_WINRT_SWAPCHAINPANELNATIVEWINDOW_H_
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Blit9.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Blit9.cpp
index a0bc2960b7..2ac8ee3a29 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Blit9.cpp
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Blit9.cpp
@@ -135,7 +135,7 @@ gl::Error Blit9::setShader(ShaderId source, const char *profile,
{
IDirect3DDevice9 *device = mRenderer->getDevice();
- D3DShaderType *shader;
+ D3DShaderType *shader = nullptr;
if (mCompiledShaders[source] != NULL)
{
@@ -236,11 +236,11 @@ gl::Error Blit9::copy2D(const gl::Framebuffer *framebuffer, const RECT &sourceRe
return error;
}
- gl::FramebufferAttachment *colorbuffer = framebuffer->getColorbuffer(0);
+ const gl::FramebufferAttachment *colorbuffer = framebuffer->getColorbuffer(0);
ASSERT(colorbuffer);
- RenderTarget9 *renderTarget9 = NULL;
- error = d3d9::GetAttachmentRenderTarget(colorbuffer, &renderTarget9);
+ RenderTarget9 *renderTarget9 = nullptr;
+ error = colorbuffer->getRenderTarget(&renderTarget9);
if (error.isError())
{
return error;
@@ -251,10 +251,11 @@ gl::Error Blit9::copy2D(const gl::Framebuffer *framebuffer, const RECT &sourceRe
ASSERT(source);
IDirect3DSurface9 *destSurface = NULL;
- TextureStorage9_2D *storage9 = TextureStorage9_2D::makeTextureStorage9_2D(storage);
- error = storage9->getSurfaceLevel(level, true, &destSurface);
+ TextureStorage9 *storage9 = GetAs<TextureStorage9>(storage);
+ error = storage9->getSurfaceLevel(GL_TEXTURE_2D, level, true, &destSurface);
if (error.isError())
{
+ SafeRelease(source);
return error;
}
ASSERT(destSurface);
@@ -275,11 +276,11 @@ gl::Error Blit9::copyCube(const gl::Framebuffer *framebuffer, const RECT &source
return error;
}
- gl::FramebufferAttachment *colorbuffer = framebuffer->getColorbuffer(0);
+ const gl::FramebufferAttachment *colorbuffer = framebuffer->getColorbuffer(0);
ASSERT(colorbuffer);
- RenderTarget9 *renderTarget9 = NULL;
- error = d3d9::GetAttachmentRenderTarget(colorbuffer, &renderTarget9);
+ RenderTarget9 *renderTarget9 = nullptr;
+ error = colorbuffer->getRenderTarget(&renderTarget9);
if (error.isError())
{
return error;
@@ -290,10 +291,11 @@ gl::Error Blit9::copyCube(const gl::Framebuffer *framebuffer, const RECT &source
ASSERT(source);
IDirect3DSurface9 *destSurface = NULL;
- TextureStorage9_Cube *storage9 = TextureStorage9_Cube::makeTextureStorage9_Cube(storage);
- error = storage9->getCubeMapSurface(target, level, true, &destSurface);
+ TextureStorage9 *storage9 = GetAs<TextureStorage9>(storage);
+ error = storage9->getSurfaceLevel(target, level, true, &destSurface);
if (error.isError())
{
+ SafeRelease(source);
return error;
}
ASSERT(destSurface);
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Buffer9.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Buffer9.cpp
index b051c81aa8..804b6971ce 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Buffer9.cpp
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Buffer9.cpp
@@ -14,7 +14,6 @@ namespace rx
Buffer9::Buffer9(Renderer9 *renderer)
: BufferD3D(renderer),
- mRenderer(renderer),
mSize(0)
{}
@@ -23,12 +22,6 @@ Buffer9::~Buffer9()
mSize = 0;
}
-Buffer9 *Buffer9::makeBuffer9(BufferImpl *buffer)
-{
- ASSERT(HAS_DYNAMIC_TYPE(Buffer9*, buffer));
- return static_cast<Buffer9*>(buffer);
-}
-
gl::Error Buffer9::setData(const void* data, size_t size, GLenum usage)
{
if (size > mMemory.size())
@@ -45,13 +38,9 @@ gl::Error Buffer9::setData(const void* data, size_t size, GLenum usage)
memcpy(mMemory.data(), data, size);
}
- invalidateStaticData();
-
- if (usage == GL_STATIC_DRAW)
- {
- initializeStaticData();
- }
+ invalidateStaticData(D3D_BUFFER_INVALIDATE_WHOLE_CACHE);
+ updateD3DBufferUsage(usage);
return gl::Error(GL_NO_ERROR);
}
@@ -77,7 +66,7 @@ gl::Error Buffer9::setSubData(const void* data, size_t size, size_t offset)
memcpy(mMemory.data() + offset, data, size);
}
- invalidateStaticData();
+ invalidateStaticData(D3D_BUFFER_INVALIDATE_WHOLE_CACHE);
return gl::Error(GL_NO_ERROR);
}
@@ -85,24 +74,30 @@ gl::Error Buffer9::setSubData(const void* data, size_t size, size_t offset)
gl::Error Buffer9::copySubData(BufferImpl* source, GLintptr sourceOffset, GLintptr destOffset, GLsizeiptr size)
{
// Note: this method is currently unreachable
- Buffer9* sourceBuffer = makeBuffer9(source);
+ Buffer9* sourceBuffer = GetAs<Buffer9>(source);
ASSERT(sourceBuffer);
memcpy(mMemory.data() + destOffset, sourceBuffer->mMemory.data() + sourceOffset, size);
- invalidateStaticData();
+ invalidateStaticData(D3D_BUFFER_INVALIDATE_WHOLE_CACHE);
return gl::Error(GL_NO_ERROR);
}
// We do not support buffer mapping in D3D9
-gl::Error Buffer9::map(size_t offset, size_t length, GLbitfield access, GLvoid **mapPtr)
+gl::Error Buffer9::map(GLenum access, GLvoid **mapPtr)
+{
+ UNREACHABLE();
+ return gl::Error(GL_INVALID_OPERATION);
+}
+
+gl::Error Buffer9::mapRange(size_t offset, size_t length, GLbitfield access, GLvoid **mapPtr)
{
UNREACHABLE();
return gl::Error(GL_INVALID_OPERATION);
}
-gl::Error Buffer9::unmap()
+gl::Error Buffer9::unmap(GLboolean *result)
{
UNREACHABLE();
return gl::Error(GL_INVALID_OPERATION);
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Buffer9.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Buffer9.h
index c1984146fc..44a524ba28 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Buffer9.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Buffer9.h
@@ -23,23 +23,21 @@ class Buffer9 : public BufferD3D
Buffer9(Renderer9 *renderer);
virtual ~Buffer9();
- static Buffer9 *makeBuffer9(BufferImpl *buffer);
-
// BufferD3D implementation
virtual size_t getSize() const { return mSize; }
virtual bool supportsDirectBinding() const { return false; }
+ gl::Error getData(const uint8_t **outData) override;
// BufferImpl implementation
virtual gl::Error setData(const void* data, size_t size, GLenum usage);
- gl::Error getData(const uint8_t **outData) override;
virtual gl::Error setSubData(const void* data, size_t size, size_t offset);
virtual gl::Error copySubData(BufferImpl* source, GLintptr sourceOffset, GLintptr destOffset, GLsizeiptr size);
- virtual gl::Error map(size_t offset, size_t length, GLbitfield access, GLvoid **mapPtr);
- virtual gl::Error unmap();
+ virtual gl::Error map(GLenum access, GLvoid **mapPtr);
+ virtual gl::Error mapRange(size_t offset, size_t length, GLbitfield access, GLvoid **mapPtr);
+ virtual gl::Error unmap(GLboolean *result);
virtual void markTransformFeedbackUsage();
private:
- Renderer9 *mRenderer;
MemoryBuffer mMemory;
size_t mSize;
};
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/DebugAnnotator9.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/DebugAnnotator9.cpp
index 09b229bcb1..6ec35e16a7 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/DebugAnnotator9.cpp
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/DebugAnnotator9.cpp
@@ -13,9 +13,9 @@
namespace rx
{
-void DebugAnnotator9::beginEvent(const std::wstring &eventName)
+void DebugAnnotator9::beginEvent(const wchar_t *eventName)
{
- D3DPERF_BeginEvent(0, eventName.c_str());
+ D3DPERF_BeginEvent(0, eventName);
}
void DebugAnnotator9::endEvent()
@@ -23,9 +23,9 @@ void DebugAnnotator9::endEvent()
D3DPERF_EndEvent();
}
-void DebugAnnotator9::setMarker(const std::wstring &markerName)
+void DebugAnnotator9::setMarker(const wchar_t *markerName)
{
- D3DPERF_SetMarker(0, markerName.c_str());
+ D3DPERF_SetMarker(0, markerName);
}
bool DebugAnnotator9::getStatus()
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/DebugAnnotator9.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/DebugAnnotator9.h
index 02956f7183..54e3bb9490 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/DebugAnnotator9.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/DebugAnnotator9.h
@@ -18,9 +18,9 @@ class DebugAnnotator9 : public gl::DebugAnnotator
{
public:
DebugAnnotator9() {}
- void beginEvent(const std::wstring &eventName) override;
+ void beginEvent(const wchar_t *eventName) override;
void endEvent() override;
- void setMarker(const std::wstring &markerName) override;
+ void setMarker(const wchar_t *markerName) override;
bool getStatus() override;
};
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Fence9.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Fence9.cpp
index 27c265e28d..3300681277 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Fence9.cpp
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Fence9.cpp
@@ -25,7 +25,7 @@ FenceNV9::~FenceNV9()
SafeRelease(mQuery);
}
-gl::Error FenceNV9::set()
+gl::Error FenceNV9::set(GLenum condition)
{
if (!mQuery)
{
@@ -47,7 +47,29 @@ gl::Error FenceNV9::set()
return gl::Error(GL_NO_ERROR);
}
-gl::Error FenceNV9::test(bool flushCommandBuffer, GLboolean *outFinished)
+gl::Error FenceNV9::test(GLboolean *outFinished)
+{
+ return testHelper(true, outFinished);
+}
+
+gl::Error FenceNV9::finish()
+{
+ GLboolean finished = GL_FALSE;
+ while (finished != GL_TRUE)
+ {
+ gl::Error error = testHelper(true, &finished);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ Sleep(0);
+ }
+
+ return gl::Error(GL_NO_ERROR);
+}
+
+gl::Error FenceNV9::testHelper(bool flushCommandBuffer, GLboolean *outFinished)
{
ASSERT(mQuery);
@@ -69,22 +91,4 @@ gl::Error FenceNV9::test(bool flushCommandBuffer, GLboolean *outFinished)
return gl::Error(GL_NO_ERROR);
}
-gl::Error FenceNV9::finishFence(GLboolean *outFinished)
-{
- ASSERT(outFinished);
-
- while (*outFinished != GL_TRUE)
- {
- gl::Error error = test(true, outFinished);
- if (error.isError())
- {
- return error;
- }
-
- Sleep(0);
- }
-
- return gl::Error(GL_NO_ERROR);
-}
-
}
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Fence9.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Fence9.h
index 4b86747396..200ac68d27 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Fence9.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Fence9.h
@@ -20,13 +20,15 @@ class FenceNV9 : public FenceNVImpl
{
public:
explicit FenceNV9(Renderer9 *renderer);
- virtual ~FenceNV9();
+ ~FenceNV9() override;
- gl::Error set();
- gl::Error test(bool flushCommandBuffer, GLboolean *outFinished);
- gl::Error finishFence(GLboolean *outFinished);
+ gl::Error set(GLenum condition) override;
+ gl::Error test(GLboolean *outFinished) override;
+ gl::Error finish() override;
private:
+ gl::Error testHelper(bool flushCommandBuffer, GLboolean *outFinished);
+
Renderer9 *mRenderer;
IDirect3DQuery9 *mQuery;
};
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Framebuffer9.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Framebuffer9.cpp
index dbdfc6d6de..9c269a8565 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Framebuffer9.cpp
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Framebuffer9.cpp
@@ -22,8 +22,7 @@ namespace rx
{
Framebuffer9::Framebuffer9(const gl::Framebuffer::Data &data, Renderer9 *renderer)
- : FramebufferD3D(data, renderer),
- mRenderer(renderer)
+ : FramebufferD3D(data, renderer), mRenderer(renderer)
{
ASSERT(mRenderer != nullptr);
}
@@ -32,9 +31,30 @@ Framebuffer9::~Framebuffer9()
{
}
-gl::Error Framebuffer9::clear(const gl::State &state, const ClearParameters &clearParams)
+gl::Error Framebuffer9::discard(size_t, const GLenum *)
{
- const gl::FramebufferAttachment *colorAttachment = mData.mColorAttachments[0];
+ // Extension not implemented in D3D9 renderer
+ UNREACHABLE();
+ return gl::Error(GL_NO_ERROR);
+}
+
+gl::Error Framebuffer9::invalidate(size_t, const GLenum *)
+{
+ // Shouldn't ever reach here in D3D9
+ UNREACHABLE();
+ return gl::Error(GL_NO_ERROR);
+}
+
+gl::Error Framebuffer9::invalidateSub(size_t, const GLenum *, const gl::Rectangle &)
+{
+ // Shouldn't ever reach here in D3D9
+ UNREACHABLE();
+ return gl::Error(GL_NO_ERROR);
+}
+
+gl::Error Framebuffer9::clear(const gl::Data &data, const ClearParameters &clearParams)
+{
+ const gl::FramebufferAttachment *colorAttachment = mData.getColorAttachment(0);
const gl::FramebufferAttachment *depthStencilAttachment = mData.getDepthOrStencilAttachment();
gl::Error error = mRenderer->applyRenderTarget(colorAttachment, depthStencilAttachment);
@@ -43,24 +63,30 @@ gl::Error Framebuffer9::clear(const gl::State &state, const ClearParameters &cle
return error;
}
- float nearZ, farZ;
- state.getDepthRange(&nearZ, &farZ);
- mRenderer->setViewport(state.getViewport(), nearZ, farZ, GL_TRIANGLES, state.getRasterizerState().frontFace, true);
+ float nearZ = data.state->getNearPlane();
+ float farZ = data.state->getFarPlane();
+ mRenderer->setViewport(data.caps, data.state->getViewport(), nearZ, farZ, GL_TRIANGLES,
+ data.state->getRasterizerState().frontFace, true);
- mRenderer->setScissorRectangle(state.getScissor(), state.isScissorTestEnabled());
+ mRenderer->setScissorRectangle(data.state->getScissor(), data.state->isScissorTestEnabled());
return mRenderer->clear(clearParams, colorAttachment, depthStencilAttachment);
}
-gl::Error Framebuffer9::readPixels(const gl::Rectangle &area, GLenum format, GLenum type, size_t outputPitch, const gl::PixelPackState &pack, uint8_t *pixels) const
+gl::Error Framebuffer9::readPixelsImpl(const gl::Rectangle &area,
+ GLenum format,
+ GLenum type,
+ size_t outputPitch,
+ const gl::PixelPackState &pack,
+ uint8_t *pixels) const
{
- ASSERT(pack.pixelBuffer.get() == NULL);
+ ASSERT(pack.pixelBuffer.get() == nullptr);
- const gl::FramebufferAttachment *colorbuffer = mData.mColorAttachments[0];
+ const gl::FramebufferAttachment *colorbuffer = mData.getColorAttachment(0);
ASSERT(colorbuffer);
- RenderTarget9 *renderTarget = NULL;
- gl::Error error = d3d9::GetAttachmentRenderTarget(colorbuffer, &renderTarget);
+ RenderTarget9 *renderTarget = nullptr;
+ gl::Error error = colorbuffer->getRenderTarget(&renderTarget);
if (error.isError())
{
return error;
@@ -84,7 +110,7 @@ gl::Error Framebuffer9::readPixels(const gl::Rectangle &area, GLenum format, GLe
ASSERT(device);
HRESULT result;
- IDirect3DSurface9 *systemSurface = NULL;
+ IDirect3DSurface9 *systemSurface = nullptr;
bool directToPixels = !pack.reverseRowOrder && pack.alignment <= 4 && mRenderer->getShareHandleSupport() &&
area.x == 0 && area.y == 0 &&
static_cast<UINT>(area.width) == desc.Width && static_cast<UINT>(area.height) == desc.Height &&
@@ -104,7 +130,7 @@ gl::Error Framebuffer9::readPixels(const gl::Rectangle &area, GLenum format, GLe
if (!directToPixels)
{
result = device->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format,
- D3DPOOL_SYSTEMMEM, &systemSurface, NULL);
+ D3DPOOL_SYSTEMMEM, &systemSurface, nullptr);
if (FAILED(result))
{
ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
@@ -246,19 +272,19 @@ gl::Error Framebuffer9::blit(const gl::Rectangle &sourceArea, const gl::Rectangl
const gl::FramebufferAttachment *readBuffer = sourceFramebuffer->getColorbuffer(0);
ASSERT(readBuffer);
- RenderTarget9 *readRenderTarget = NULL;
- gl::Error error = d3d9::GetAttachmentRenderTarget(readBuffer, &readRenderTarget);
+ RenderTarget9 *readRenderTarget = nullptr;
+ gl::Error error = readBuffer->getRenderTarget(&readRenderTarget);
if (error.isError())
{
return error;
}
ASSERT(readRenderTarget);
- const gl::FramebufferAttachment *drawBuffer = mData.mColorAttachments[0];
+ const gl::FramebufferAttachment *drawBuffer = mData.getColorAttachment(0);
ASSERT(drawBuffer);
- RenderTarget9 *drawRenderTarget = NULL;
- error = d3d9::GetAttachmentRenderTarget(drawBuffer, &drawRenderTarget);
+ RenderTarget9 *drawRenderTarget = nullptr;
+ error = drawBuffer->getRenderTarget(&drawRenderTarget);
if (error.isError())
{
return error;
@@ -372,8 +398,8 @@ gl::Error Framebuffer9::blit(const gl::Rectangle &sourceArea, const gl::Rectangl
const gl::FramebufferAttachment *readBuffer = sourceFramebuffer->getDepthOrStencilbuffer();
ASSERT(readBuffer);
- RenderTarget9 *readDepthStencil = NULL;
- gl::Error error = d3d9::GetAttachmentRenderTarget(readBuffer, &readDepthStencil);
+ RenderTarget9 *readDepthStencil = nullptr;
+ gl::Error error = readBuffer->getRenderTarget(&readDepthStencil);
if (error.isError())
{
return error;
@@ -383,8 +409,8 @@ gl::Error Framebuffer9::blit(const gl::Rectangle &sourceArea, const gl::Rectangl
const gl::FramebufferAttachment *drawBuffer = mData.getDepthOrStencilAttachment();
ASSERT(drawBuffer);
- RenderTarget9 *drawDepthStencil = NULL;
- error = d3d9::GetAttachmentRenderTarget(drawBuffer, &drawDepthStencil);
+ RenderTarget9 *drawDepthStencil = nullptr;
+ error = drawBuffer->getRenderTarget(&drawDepthStencil);
if (error.isError())
{
return error;
@@ -398,7 +424,7 @@ gl::Error Framebuffer9::blit(const gl::Rectangle &sourceArea, const gl::Rectangl
IDirect3DSurface9* drawSurface = drawDepthStencil->getSurface();
ASSERT(drawDepthStencil);
- HRESULT result = device->StretchRect(readSurface, NULL, drawSurface, NULL, D3DTEXF_NONE);
+ HRESULT result = device->StretchRect(readSurface, nullptr, drawSurface, nullptr, D3DTEXF_NONE);
SafeRelease(readSurface);
SafeRelease(drawSurface);
@@ -414,7 +440,7 @@ gl::Error Framebuffer9::blit(const gl::Rectangle &sourceArea, const gl::Rectangl
GLenum Framebuffer9::getRenderTargetImplementationFormat(RenderTargetD3D *renderTarget) const
{
- RenderTarget9 *renderTarget9 = RenderTarget9::makeRenderTarget9(renderTarget);
+ RenderTarget9 *renderTarget9 = GetAs<RenderTarget9>(renderTarget);
const d3d9::D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(renderTarget9->getD3DFormat());
return d3dFormatInfo.internalFormat;
}
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Framebuffer9.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Framebuffer9.h
index 292118e6db..fe12079ae0 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Framebuffer9.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Framebuffer9.h
@@ -21,11 +21,19 @@ class Framebuffer9 : public FramebufferD3D
Framebuffer9(const gl::Framebuffer::Data &data, Renderer9 *renderer);
virtual ~Framebuffer9();
- private:
- gl::Error clear(const gl::State &state, const ClearParameters &clearParams) override;
+ gl::Error discard(size_t count, const GLenum *attachments) override;
+ gl::Error invalidate(size_t count, const GLenum *attachments) override;
+ gl::Error invalidateSub(size_t count, const GLenum *attachments, const gl::Rectangle &area) override;
- gl::Error readPixels(const gl::Rectangle &area, GLenum format, GLenum type, size_t outputPitch,
- const gl::PixelPackState &pack, uint8_t *pixels) const override;
+ private:
+ gl::Error clear(const gl::Data &data, const ClearParameters &clearParams) override;
+
+ gl::Error readPixelsImpl(const gl::Rectangle &area,
+ GLenum format,
+ GLenum type,
+ size_t outputPitch,
+ const gl::PixelPackState &pack,
+ uint8_t *pixels) const override;
gl::Error blit(const gl::Rectangle &sourceArea, const gl::Rectangle &destArea, const gl::Rectangle *scissor,
bool blitRenderTarget, bool blitDepth, bool blitStencil, GLenum filter,
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Image9.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Image9.cpp
index d149f7a806..fec7e3e19d 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Image9.cpp
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Image9.cpp
@@ -94,12 +94,6 @@ gl::Error Image9::generateMip(IDirect3DSurface9 *destSurface, IDirect3DSurface9
return gl::Error(GL_NO_ERROR);
}
-Image9 *Image9::makeImage9(ImageD3D *img)
-{
- ASSERT(HAS_DYNAMIC_TYPE(Image9*, img));
- return static_cast<Image9*>(img);
-}
-
gl::Error Image9::generateMipmap(Image9 *dest, Image9 *source)
{
IDirect3DSurface9 *sourceSurface = NULL;
@@ -336,8 +330,8 @@ gl::Error Image9::getSurface(IDirect3DSurface9 **outSurface)
gl::Error Image9::setManagedSurface2D(TextureStorage *storage, int level)
{
IDirect3DSurface9 *surface = NULL;
- TextureStorage9_2D *storage9 = TextureStorage9_2D::makeTextureStorage9_2D(storage);
- gl::Error error = storage9->getSurfaceLevel(level, false, &surface);
+ TextureStorage9 *storage9 = GetAs<TextureStorage9>(storage);
+ gl::Error error = storage9->getSurfaceLevel(GL_TEXTURE_2D, level, false, &surface);
if (error.isError())
{
return error;
@@ -348,8 +342,9 @@ gl::Error Image9::setManagedSurface2D(TextureStorage *storage, int level)
gl::Error Image9::setManagedSurfaceCube(TextureStorage *storage, int face, int level)
{
IDirect3DSurface9 *surface = NULL;
- TextureStorage9_Cube *storage9 = TextureStorage9_Cube::makeTextureStorage9_Cube(storage);
- gl::Error error = storage9->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level, false, &surface);
+ TextureStorage9 *storage9 = GetAs<TextureStorage9>(storage);
+ gl::Error error =
+ storage9->getSurfaceLevel(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level, false, &surface);
if (error.isError())
{
return error;
@@ -390,12 +385,13 @@ gl::Error Image9::copyToStorage(TextureStorage *storage, const gl::ImageIndex &i
return error;
}
+ TextureStorage9 *storage9 = GetAs<TextureStorage9>(storage);
+
IDirect3DSurface9 *destSurface = NULL;
if (index.type == GL_TEXTURE_2D)
{
- TextureStorage9_2D *storage9 = TextureStorage9_2D::makeTextureStorage9_2D(storage);
- error = storage9->getSurfaceLevel(index.mipIndex, true, &destSurface);
+ error = storage9->getSurfaceLevel(GL_TEXTURE_2D, index.mipIndex, true, &destSurface);
if (error.isError())
{
return error;
@@ -404,8 +400,7 @@ gl::Error Image9::copyToStorage(TextureStorage *storage, const gl::ImageIndex &i
else
{
ASSERT(gl::IsCubeMapTextureTarget(index.type));
- TextureStorage9_Cube *storage9 = TextureStorage9_Cube::makeTextureStorage9_Cube(storage);
- error = storage9->getCubeMapSurface(index.type, index.mipIndex, true, &destSurface);
+ error = storage9->getSurfaceLevel(index.type, index.mipIndex, true, &destSurface);
if (error.isError())
{
return error;
@@ -485,6 +480,8 @@ gl::Error Image9::loadData(const gl::Box &area, const gl::PixelUnpackState &unpa
const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(mInternalFormat);
GLsizei inputRowPitch = formatInfo.computeRowPitch(type, area.width, unpack.alignment, unpack.rowLength);
+ GLsizei inputSkipBytes = formatInfo.computeSkipPixels(inputRowPitch, 0, unpack.skipImages,
+ unpack.skipRows, unpack.skipPixels);
const d3d9::TextureFormat &d3dFormatInfo = d3d9::GetTextureFormatInfo(mInternalFormat);
ASSERT(d3dFormatInfo.loadFunction != NULL);
@@ -503,8 +500,9 @@ gl::Error Image9::loadData(const gl::Box &area, const gl::PixelUnpackState &unpa
}
d3dFormatInfo.loadFunction(area.width, area.height, area.depth,
- reinterpret_cast<const uint8_t*>(input), inputRowPitch, 0,
- reinterpret_cast<uint8_t*>(locked.pBits), locked.Pitch, 0);
+ reinterpret_cast<const uint8_t *>(input) + inputSkipBytes,
+ inputRowPitch, 0, reinterpret_cast<uint8_t *>(locked.pBits),
+ locked.Pitch, 0);
unlock();
@@ -518,7 +516,8 @@ gl::Error Image9::loadCompressedData(const gl::Box &area, const void *input)
const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(mInternalFormat);
GLsizei inputRowPitch = formatInfo.computeRowPitch(GL_UNSIGNED_BYTE, area.width, 1, 0);
- GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, area.width, area.height, 1, 0);
+ GLsizei inputDepthPitch =
+ formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, area.width, area.height, 1, 0, 0);
const d3d9::TextureFormat &d3d9FormatInfo = d3d9::GetTextureFormatInfo(mInternalFormat);
@@ -550,14 +549,16 @@ gl::Error Image9::loadCompressedData(const gl::Box &area, const void *input)
}
// This implements glCopyTex[Sub]Image2D for non-renderable internal texture formats and incomplete textures
-gl::Error Image9::copy(const gl::Offset &destOffset, const gl::Rectangle &sourceArea, RenderTargetD3D *source)
+gl::Error Image9::copyFromRTInternal(const gl::Offset &destOffset,
+ const gl::Rectangle &sourceArea,
+ RenderTargetD3D *source)
{
ASSERT(source);
// ES3.0 only behaviour to copy into a 3d texture
ASSERT(destOffset.z == 0);
- RenderTarget9 *renderTarget = RenderTarget9::makeRenderTarget9(source);
+ RenderTarget9 *renderTarget = GetAs<RenderTarget9>(source);
IDirect3DSurface9 *surface = renderTarget->getSurface();
ASSERT(surface);
@@ -667,9 +668,9 @@ gl::Error Image9::copy(const gl::Offset &destOffset, const gl::Rectangle &source
for (int x = 0; x < width; x++)
{
unsigned short rgb = ((unsigned short*)sourcePixels)[x];
- unsigned char red = (rgb & 0xF800) >> 8;
- unsigned char green = (rgb & 0x07E0) >> 3;
- unsigned char blue = (rgb & 0x001F) << 3;
+ unsigned char red = static_cast<unsigned char>((rgb & 0xF800) >> 8);
+ unsigned char green = static_cast<unsigned char>((rgb & 0x07E0) >> 3);
+ unsigned char blue = static_cast<unsigned char>((rgb & 0x001F) << 3);
destPixels[x + 0] = blue | (blue >> 5);
destPixels[x + 1] = green | (green >> 6);
destPixels[x + 2] = red | (red >> 5);
@@ -704,9 +705,9 @@ gl::Error Image9::copy(const gl::Offset &destOffset, const gl::Rectangle &source
for (int x = 0; x < width; x++)
{
unsigned short argb = ((unsigned short*)sourcePixels)[x];
- unsigned char red = (argb & 0x7C00) >> 7;
- unsigned char green = (argb & 0x03E0) >> 2;
- unsigned char blue = (argb & 0x001F) << 3;
+ unsigned char red = static_cast<unsigned char>((argb & 0x7C00) >> 7);
+ unsigned char green = static_cast<unsigned char>((argb & 0x03E0) >> 2);
+ unsigned char blue = static_cast<unsigned char>((argb & 0x001F) << 3);
destPixels[x + 0] = blue | (blue >> 5);
destPixels[x + 1] = green | (green >> 5);
destPixels[x + 2] = red | (red >> 5);
@@ -722,9 +723,9 @@ gl::Error Image9::copy(const gl::Offset &destOffset, const gl::Rectangle &source
for (int x = 0; x < width; x++)
{
unsigned short argb = ((unsigned short*)sourcePixels)[x];
- unsigned char red = (argb & 0x7C00) >> 7;
- unsigned char green = (argb & 0x03E0) >> 2;
- unsigned char blue = (argb & 0x001F) << 3;
+ unsigned char red = static_cast<unsigned char>((argb & 0x7C00) >> 7);
+ unsigned char green = static_cast<unsigned char>((argb & 0x03E0) >> 2);
+ unsigned char blue = static_cast<unsigned char>((argb & 0x001F) << 3);
unsigned char alpha = (signed short)argb >> 15;
destPixels[x + 0] = blue | (blue >> 5);
destPixels[x + 1] = green | (green >> 5);
@@ -778,11 +779,35 @@ gl::Error Image9::copy(const gl::Offset &destOffset, const gl::Rectangle &source
return gl::Error(GL_NO_ERROR);
}
-gl::Error Image9::copy(const gl::Offset &destOffset, const gl::Box &area, const gl::ImageIndex &srcIndex, TextureStorage *srcStorage)
+gl::Error Image9::copyFromTexStorage(const gl::ImageIndex &imageIndex, TextureStorage *source)
{
- // Currently unreachable, due to only being used in a D3D11-only workaround
- UNIMPLEMENTED();
- return gl::Error(GL_INVALID_OPERATION);
+ RenderTargetD3D *renderTarget = nullptr;
+ gl::Error error = source->getRenderTarget(imageIndex, &renderTarget);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ gl::Rectangle sourceArea(0, 0, mWidth, mHeight);
+ return copyFromRTInternal(gl::Offset(), sourceArea, renderTarget);
}
+gl::Error Image9::copyFromFramebuffer(const gl::Offset &destOffset,
+ const gl::Rectangle &sourceArea,
+ const gl::Framebuffer *source)
+{
+ const gl::FramebufferAttachment *srcAttachment = source->getReadColorbuffer();
+ ASSERT(srcAttachment);
+
+ RenderTargetD3D *renderTarget = NULL;
+ gl::Error error = srcAttachment->getRenderTarget(&renderTarget);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ ASSERT(renderTarget);
+ return copyFromRTInternal(destOffset, sourceArea, renderTarget);
}
+
+} // namespace rx
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Image9.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Image9.h
index 8cbfbbebf6..91448cc849 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Image9.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Image9.h
@@ -28,8 +28,6 @@ class Image9 : public ImageD3D
Image9(Renderer9 *renderer);
~Image9();
- static Image9 *makeImage9(ImageD3D *img);
-
static gl::Error generateMipmap(Image9 *dest, Image9 *source);
static gl::Error generateMip(IDirect3DSurface9 *destSurface, IDirect3DSurface9 *sourceSurface);
static gl::Error copyLockableSurfaces(IDirect3DSurface9 *dest, IDirect3DSurface9 *source);
@@ -47,9 +45,10 @@ class Image9 : public ImageD3D
virtual gl::Error loadData(const gl::Box &area, const gl::PixelUnpackState &unpack, GLenum type, const void *input);
virtual gl::Error loadCompressedData(const gl::Box &area, const void *input);
- virtual gl::Error copy(const gl::Offset &destOffset, const gl::Rectangle &sourceArea, RenderTargetD3D *source);
- virtual gl::Error copy(const gl::Offset &destOffset, const gl::Box &sourceArea,
- const gl::ImageIndex &sourceIndex, TextureStorage *source);
+ gl::Error copyFromTexStorage(const gl::ImageIndex &imageIndex, TextureStorage *source) override;
+ gl::Error copyFromFramebuffer(const gl::Offset &destOffset,
+ const gl::Rectangle &sourceArea,
+ const gl::Framebuffer *source) override;
private:
gl::Error getSurface(IDirect3DSurface9 **outSurface);
@@ -61,6 +60,10 @@ class Image9 : public ImageD3D
gl::Error lock(D3DLOCKED_RECT *lockedRect, const RECT &rect);
void unlock();
+ gl::Error copyFromRTInternal(const gl::Offset &destOffset,
+ const gl::Rectangle &sourceArea,
+ RenderTargetD3D *source);
+
Renderer9 *mRenderer;
D3DPOOL mD3DPool; // can only be D3DPOOL_SYSTEMMEM or D3DPOOL_MANAGED since it needs to be lockable.
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/IndexBuffer9.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/IndexBuffer9.cpp
index c5d72e6a50..97c7f72136 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/IndexBuffer9.cpp
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/IndexBuffer9.cpp
@@ -65,12 +65,6 @@ gl::Error IndexBuffer9::initialize(unsigned int bufferSize, GLenum indexType, bo
return gl::Error(GL_NO_ERROR);
}
-IndexBuffer9 *IndexBuffer9::makeIndexBuffer9(IndexBuffer *indexBuffer)
-{
- ASSERT(HAS_DYNAMIC_TYPE(IndexBuffer9*, indexBuffer));
- return static_cast<IndexBuffer9*>(indexBuffer);
-}
-
gl::Error IndexBuffer9::mapBuffer(unsigned int offset, unsigned int size, void** outMappedMemory)
{
if (!mIndexBuffer)
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/IndexBuffer9.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/IndexBuffer9.h
index 61f8b11566..ba03ba703f 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/IndexBuffer9.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/IndexBuffer9.h
@@ -23,8 +23,6 @@ class IndexBuffer9 : public IndexBuffer
virtual gl::Error initialize(unsigned int bufferSize, GLenum indexType, bool dynamic);
- static IndexBuffer9 *makeIndexBuffer9(IndexBuffer *indexBuffer);
-
virtual gl::Error mapBuffer(unsigned int offset, unsigned int size, void** outMappedMemory);
virtual gl::Error unmapBuffer();
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Query9.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Query9.cpp
index 96f12d7868..c826abf81c 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Query9.cpp
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Query9.cpp
@@ -66,7 +66,14 @@ gl::Error Query9::end()
return gl::Error(GL_NO_ERROR);
}
-gl::Error Query9::getResult(GLuint *params)
+gl::Error Query9::queryCounter()
+{
+ UNIMPLEMENTED();
+ return gl::Error(GL_INVALID_OPERATION, "Unimplemented");
+}
+
+template <typename T>
+gl::Error Query9::getResultBase(T *params)
{
while (!mQueryFinished)
{
@@ -83,12 +90,31 @@ gl::Error Query9::getResult(GLuint *params)
}
ASSERT(mQueryFinished);
- *params = mResult;
-
+ *params = static_cast<T>(mResult);
return gl::Error(GL_NO_ERROR);
}
-gl::Error Query9::isResultAvailable(GLuint *available)
+gl::Error Query9::getResult(GLint *params)
+{
+ return getResultBase(params);
+}
+
+gl::Error Query9::getResult(GLuint *params)
+{
+ return getResultBase(params);
+}
+
+gl::Error Query9::getResult(GLint64 *params)
+{
+ return getResultBase(params);
+}
+
+gl::Error Query9::getResult(GLuint64 *params)
+{
+ return getResultBase(params);
+}
+
+gl::Error Query9::isResultAvailable(bool *available)
{
gl::Error error = testQuery();
if (error.isError())
@@ -96,7 +122,7 @@ gl::Error Query9::isResultAvailable(GLuint *available)
return error;
}
- *available = (mQueryFinished ? GL_TRUE : GL_FALSE);
+ *available = mQueryFinished;
return gl::Error(GL_NO_ERROR);
}
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Query9.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Query9.h
index 399da2ed83..9d17711a00 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Query9.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Query9.h
@@ -23,13 +23,20 @@ class Query9 : public QueryImpl
virtual gl::Error begin();
virtual gl::Error end();
+ virtual gl::Error queryCounter();
+ virtual gl::Error getResult(GLint *params);
virtual gl::Error getResult(GLuint *params);
- virtual gl::Error isResultAvailable(GLuint *available);
+ virtual gl::Error getResult(GLint64 *params);
+ virtual gl::Error getResult(GLuint64 *params);
+ virtual gl::Error isResultAvailable(bool *available);
private:
gl::Error testQuery();
- GLuint mResult;
+ template <typename T>
+ gl::Error getResultBase(T *params);
+
+ GLuint64 mResult;
bool mQueryFinished;
Renderer9 *mRenderer;
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/RenderTarget9.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/RenderTarget9.cpp
index 412c0109f5..419bff1f63 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/RenderTarget9.cpp
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/RenderTarget9.cpp
@@ -16,14 +16,14 @@
namespace rx
{
-RenderTarget9 *RenderTarget9::makeRenderTarget9(RenderTargetD3D *target)
-{
- ASSERT(HAS_DYNAMIC_TYPE(RenderTarget9*, target));
- return static_cast<RenderTarget9*>(target);
-}
-
// TODO: AddRef the incoming surface to take ownership instead of expecting that its ref is being given.
-TextureRenderTarget9::TextureRenderTarget9(IDirect3DSurface9 *surface, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth,
+TextureRenderTarget9::TextureRenderTarget9(IDirect3DBaseTexture9 *texture,
+ size_t textureLevel,
+ IDirect3DSurface9 *surface,
+ GLenum internalFormat,
+ GLsizei width,
+ GLsizei height,
+ GLsizei depth,
GLsizei samples)
: mWidth(width),
mHeight(height),
@@ -31,6 +31,8 @@ TextureRenderTarget9::TextureRenderTarget9(IDirect3DSurface9 *surface, GLenum in
mInternalFormat(internalFormat),
mD3DFormat(D3DFMT_UNKNOWN),
mSamples(samples),
+ mTexture(texture),
+ mTextureLevel(textureLevel),
mRenderTarget(surface)
{
ASSERT(mDepth == 1);
@@ -45,6 +47,7 @@ TextureRenderTarget9::TextureRenderTarget9(IDirect3DSurface9 *surface, GLenum in
TextureRenderTarget9::~TextureRenderTarget9()
{
+ SafeRelease(mTexture);
SafeRelease(mRenderTarget);
}
@@ -73,7 +76,17 @@ GLsizei TextureRenderTarget9::getSamples() const
return mSamples;
}
-IDirect3DSurface9 *TextureRenderTarget9::getSurface()
+IDirect3DBaseTexture9 *TextureRenderTarget9::getTexture() const
+{
+ return mTexture;
+}
+
+size_t TextureRenderTarget9::getTextureLevel() const
+{
+ return mTextureLevel;
+}
+
+IDirect3DSurface9 *TextureRenderTarget9::getSurface() const
{
// Caller is responsible for releasing the returned surface reference.
// TODO: remove the AddRef to match RenderTarget11
@@ -117,7 +130,7 @@ GLsizei SurfaceRenderTarget9::getDepth() const
GLenum SurfaceRenderTarget9::getInternalFormat() const
{
- return (mDepth ? mSwapChain->GetDepthBufferInternalFormat() : mSwapChain->GetBackBufferInternalFormat());
+ return (mDepth ? mSwapChain->GetDepthBufferInternalFormat() : mSwapChain->GetRenderTargetInternalFormat());
}
GLsizei SurfaceRenderTarget9::getSamples() const
@@ -126,11 +139,21 @@ GLsizei SurfaceRenderTarget9::getSamples() const
return 0;
}
-IDirect3DSurface9 *SurfaceRenderTarget9::getSurface()
+IDirect3DSurface9 *SurfaceRenderTarget9::getSurface() const
{
return (mDepth ? mSwapChain->getDepthStencil() : mSwapChain->getRenderTarget());
}
+IDirect3DBaseTexture9 *SurfaceRenderTarget9::getTexture() const
+{
+ return (mDepth ? nullptr : mSwapChain->getOffscreenTexture());
+}
+
+size_t SurfaceRenderTarget9::getTextureLevel() const
+{
+ return 0;
+}
+
D3DFORMAT SurfaceRenderTarget9::getD3DFormat() const
{
return d3d9::GetTextureFormatInfo(getInternalFormat()).texFormat;
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/RenderTarget9.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/RenderTarget9.h
index 32c7dfa09c..f19c54de7b 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/RenderTarget9.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/RenderTarget9.h
@@ -22,10 +22,12 @@ class RenderTarget9 : public RenderTargetD3D
public:
RenderTarget9() { }
virtual ~RenderTarget9() { }
+ // Retrieve the texture that backs this render target, may be null for swap chain render
+ // targets.
+ virtual IDirect3DBaseTexture9 *getTexture() const = 0;
+ virtual size_t getTextureLevel() const = 0;
- static RenderTarget9 *makeRenderTarget9(RenderTargetD3D *renderTarget);
-
- virtual IDirect3DSurface9 *getSurface() = 0;
+ virtual IDirect3DSurface9 *getSurface() const = 0;
virtual D3DFORMAT getD3DFormat() const = 0;
};
@@ -33,7 +35,13 @@ class RenderTarget9 : public RenderTargetD3D
class TextureRenderTarget9 : public RenderTarget9
{
public:
- TextureRenderTarget9(IDirect3DSurface9 *surface, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth,
+ TextureRenderTarget9(IDirect3DBaseTexture9 *texture,
+ size_t textureLevel,
+ IDirect3DSurface9 *surface,
+ GLenum internalFormat,
+ GLsizei width,
+ GLsizei height,
+ GLsizei depth,
GLsizei samples);
virtual ~TextureRenderTarget9();
@@ -43,7 +51,9 @@ class TextureRenderTarget9 : public RenderTarget9
GLenum getInternalFormat() const override;
GLsizei getSamples() const override;
- IDirect3DSurface9 *getSurface() override;
+ IDirect3DBaseTexture9 *getTexture() const override;
+ size_t getTextureLevel() const override;
+ IDirect3DSurface9 *getSurface() const override;
D3DFORMAT getD3DFormat() const override;
@@ -55,6 +65,8 @@ class TextureRenderTarget9 : public RenderTarget9
D3DFORMAT mD3DFormat;
GLsizei mSamples;
+ IDirect3DBaseTexture9 *mTexture;
+ size_t mTextureLevel;
IDirect3DSurface9 *mRenderTarget;
};
@@ -70,7 +82,9 @@ class SurfaceRenderTarget9 : public RenderTarget9
GLenum getInternalFormat() const override;
GLsizei getSamples() const override;
- IDirect3DSurface9 *getSurface() override;
+ IDirect3DBaseTexture9 *getTexture() const override;
+ size_t getTextureLevel() const override;
+ IDirect3DSurface9 *getSurface() const override;
D3DFORMAT getD3DFormat() const override;
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp
index bf1c367693..6bb975b0e4 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp
@@ -8,49 +8,50 @@
#include "libANGLE/renderer/d3d/d3d9/Renderer9.h"
+#include <sstream>
+#include <EGL/eglext.h>
+
#include "common/utilities.h"
+#include "libANGLE/angletypes.h"
#include "libANGLE/Buffer.h"
#include "libANGLE/Display.h"
+#include "libANGLE/features.h"
+#include "libANGLE/formatutils.h"
#include "libANGLE/Framebuffer.h"
#include "libANGLE/FramebufferAttachment.h"
#include "libANGLE/Program.h"
#include "libANGLE/Renderbuffer.h"
-#include "libANGLE/State.h"
-#include "libANGLE/Surface.h"
-#include "libANGLE/Texture.h"
-#include "libANGLE/angletypes.h"
-#include "libANGLE/features.h"
-#include "libANGLE/formatutils.h"
-#include "libANGLE/renderer/d3d/CompilerD3D.h"
-#include "libANGLE/renderer/d3d/FramebufferD3D.h"
-#include "libANGLE/renderer/d3d/IndexDataManager.h"
-#include "libANGLE/renderer/d3d/ProgramD3D.h"
-#include "libANGLE/renderer/d3d/RenderbufferD3D.h"
-#include "libANGLE/renderer/d3d/ShaderD3D.h"
-#include "libANGLE/renderer/d3d/SurfaceD3D.h"
-#include "libANGLE/renderer/d3d/TextureD3D.h"
-#include "libANGLE/renderer/d3d/TransformFeedbackD3D.h"
#include "libANGLE/renderer/d3d/d3d9/Blit9.h"
#include "libANGLE/renderer/d3d/d3d9/Buffer9.h"
#include "libANGLE/renderer/d3d/d3d9/Fence9.h"
+#include "libANGLE/renderer/d3d/d3d9/formatutils9.h"
#include "libANGLE/renderer/d3d/d3d9/Framebuffer9.h"
#include "libANGLE/renderer/d3d/d3d9/Image9.h"
#include "libANGLE/renderer/d3d/d3d9/IndexBuffer9.h"
#include "libANGLE/renderer/d3d/d3d9/Query9.h"
+#include "libANGLE/renderer/d3d/d3d9/renderer9_utils.h"
#include "libANGLE/renderer/d3d/d3d9/RenderTarget9.h"
#include "libANGLE/renderer/d3d/d3d9/ShaderExecutable9.h"
#include "libANGLE/renderer/d3d/d3d9/SwapChain9.h"
#include "libANGLE/renderer/d3d/d3d9/TextureStorage9.h"
#include "libANGLE/renderer/d3d/d3d9/VertexArray9.h"
#include "libANGLE/renderer/d3d/d3d9/VertexBuffer9.h"
-#include "libANGLE/renderer/d3d/d3d9/renderer9_utils.h"
-#include "libANGLE/renderer/d3d/d3d9/formatutils9.h"
-
+#include "libANGLE/renderer/d3d/CompilerD3D.h"
+#include "libANGLE/renderer/d3d/DeviceD3D.h"
+#include "libANGLE/renderer/d3d/FramebufferD3D.h"
+#include "libANGLE/renderer/d3d/IndexDataManager.h"
+#include "libANGLE/renderer/d3d/ProgramD3D.h"
+#include "libANGLE/renderer/d3d/RenderbufferD3D.h"
+#include "libANGLE/renderer/d3d/ShaderD3D.h"
+#include "libANGLE/renderer/d3d/SurfaceD3D.h"
+#include "libANGLE/renderer/d3d/TextureD3D.h"
+#include "libANGLE/renderer/d3d/TransformFeedbackD3D.h"
+#include "libANGLE/State.h"
+#include "libANGLE/Surface.h"
+#include "libANGLE/Texture.h"
#include "third_party/trace_event/trace_event.h"
-#include <sstream>
-#include <EGL/eglext.h>
#if !defined(ANGLE_COMPILE_OPTIMIZATION_LEVEL)
#define ANGLE_COMPILE_OPTIMIZATION_LEVEL D3DCOMPILE_OPTIMIZATION_LEVEL3
@@ -76,12 +77,8 @@ enum
MAX_TEXTURE_IMAGE_UNITS_VTF_SM3 = 4
};
-Renderer9::Renderer9(egl::Display *display)
- : RendererD3D(display)
+Renderer9::Renderer9(egl::Display *display) : RendererD3D(display), mStateManager(this)
{
- // Initialize global annotator
- gl::InitializeDebugAnnotations(&mAnnotator);
-
mD3d9Module = NULL;
mD3d9 = NULL;
@@ -133,6 +130,10 @@ Renderer9::Renderer9(egl::Display *display)
mAppliedVertexShader = NULL;
mAppliedPixelShader = NULL;
mAppliedProgramSerial = 0;
+
+ initializeDebugAnnotator();
+
+ mEGLDevice = nullptr;
}
Renderer9::~Renderer9()
@@ -147,8 +148,6 @@ Renderer9::~Renderer9()
}
release();
-
- gl::UninitializeDebugAnnotations();
}
void Renderer9::release()
@@ -157,6 +156,7 @@ void Renderer9::release()
releaseDeviceResources();
+ SafeDelete(mEGLDevice);
SafeRelease(mDevice);
SafeRelease(mDeviceEx);
SafeRelease(mD3d9);
@@ -173,22 +173,9 @@ void Renderer9::release()
mD3d9Module = NULL;
}
-Renderer9 *Renderer9::makeRenderer9(Renderer *renderer)
-{
- ASSERT(HAS_DYNAMIC_TYPE(Renderer9*, renderer));
- return static_cast<Renderer9*>(renderer);
-}
-
egl::Error Renderer9::initialize()
{
- if (!mCompiler.initialize())
- {
- return egl::Error(EGL_NOT_INITIALIZED,
- D3D9_INIT_COMPILER_ERROR,
- "Compiler failed to initialize.");
- }
-
- TRACE_EVENT0("gpu", "GetModuleHandle_d3d9");
+ TRACE_EVENT0("gpu.angle", "GetModuleHandle_d3d9");
mD3d9Module = GetModuleHandle(TEXT("d3d9.dll"));
if (mD3d9Module == NULL)
@@ -204,14 +191,14 @@ egl::Error Renderer9::initialize()
// desktop. Direct3D9Ex is available in Windows Vista and later if suitable drivers are available.
if (ANGLE_D3D9EX == ANGLE_ENABLED && Direct3DCreate9ExPtr && SUCCEEDED(Direct3DCreate9ExPtr(D3D_SDK_VERSION, &mD3d9Ex)))
{
- TRACE_EVENT0("gpu", "D3d9Ex_QueryInterface");
+ TRACE_EVENT0("gpu.angle", "D3d9Ex_QueryInterface");
ASSERT(mD3d9Ex);
mD3d9Ex->QueryInterface(IID_IDirect3D9, reinterpret_cast<void**>(&mD3d9));
ASSERT(mD3d9);
}
else
{
- TRACE_EVENT0("gpu", "Direct3DCreate9");
+ TRACE_EVENT0("gpu.angle", "Direct3DCreate9");
mD3d9 = Direct3DCreate9(D3D_SDK_VERSION);
}
@@ -229,7 +216,7 @@ egl::Error Renderer9::initialize()
// Give up on getting device caps after about one second.
{
- TRACE_EVENT0("gpu", "GetDeviceCaps");
+ TRACE_EVENT0("gpu.angle", "GetDeviceCaps");
for (int i = 0; i < 10; ++i)
{
result = mD3d9->GetDeviceCaps(mAdapter, mDeviceType, &mDeviceCaps);
@@ -273,7 +260,7 @@ egl::Error Renderer9::initialize()
}
{
- TRACE_EVENT0("gpu", "GetAdapterIdentifier");
+ TRACE_EVENT0("gpu.angle", "GetAdapterIdentifier");
mD3d9->GetAdapterIdentifier(mAdapter, 0, &mAdapterIdentifier);
}
@@ -281,7 +268,7 @@ egl::Error Renderer9::initialize()
static const TCHAR className[] = TEXT("STATIC");
{
- TRACE_EVENT0("gpu", "CreateWindowEx");
+ TRACE_EVENT0("gpu.angle", "CreateWindowEx");
mDeviceWindow = CreateWindowEx(WS_EX_NOACTIVATE, className, windowName, WS_DISABLED | WS_POPUP, 0, 0, 1, 1, HWND_MESSAGE, NULL, GetModuleHandle(NULL), NULL);
}
@@ -289,7 +276,7 @@ egl::Error Renderer9::initialize()
DWORD behaviorFlags = D3DCREATE_FPU_PRESERVE | D3DCREATE_NOWINDOWCHANGES | D3DCREATE_MULTITHREADED;
{
- TRACE_EVENT0("gpu", "D3d9_CreateDevice");
+ TRACE_EVENT0("gpu.angle", "D3d9_CreateDevice");
result = mD3d9->CreateDevice(mAdapter, mDeviceType, mDeviceWindow, behaviorFlags | D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE, &presentParameters, &mDevice);
}
if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_DEVICELOST)
@@ -300,7 +287,7 @@ egl::Error Renderer9::initialize()
if (FAILED(result))
{
- TRACE_EVENT0("gpu", "D3d9_CreateDevice2");
+ TRACE_EVENT0("gpu.angle", "D3d9_CreateDevice2");
result = mD3d9->CreateDevice(mAdapter, mDeviceType, mDeviceWindow, behaviorFlags | D3DCREATE_SOFTWARE_VERTEXPROCESSING, &presentParameters, &mDevice);
if (FAILED(result))
@@ -313,13 +300,13 @@ egl::Error Renderer9::initialize()
if (mD3d9Ex)
{
- TRACE_EVENT0("gpu", "mDevice_QueryInterface");
+ TRACE_EVENT0("gpu.angle", "mDevice_QueryInterface");
result = mDevice->QueryInterface(IID_IDirect3DDevice9Ex, (void**)&mDeviceEx);
ASSERT(SUCCEEDED(result));
}
{
- TRACE_EVENT0("gpu", "ShaderCache initialize");
+ TRACE_EVENT0("gpu.angle", "ShaderCache initialize");
mVertexShaderCache.initialize(mDevice);
mPixelShaderCache.initialize(mDevice);
}
@@ -359,14 +346,11 @@ void Renderer9::initializeDevice()
const gl::Caps &rendererCaps = getRendererCaps();
- mForceSetVertexSamplerStates.resize(rendererCaps.maxVertexTextureImageUnits);
mCurVertexSamplerStates.resize(rendererCaps.maxVertexTextureImageUnits);
-
- mForceSetPixelSamplerStates.resize(rendererCaps.maxTextureImageUnits);
mCurPixelSamplerStates.resize(rendererCaps.maxTextureImageUnits);
- mCurVertexTextureSerials.resize(rendererCaps.maxVertexTextureImageUnits);
- mCurPixelTextureSerials.resize(rendererCaps.maxTextureImageUnits);
+ mCurVertexTextures.resize(rendererCaps.maxVertexTextureImageUnits);
+ mCurPixelTextures.resize(rendererCaps.maxTextureImageUnits);
markAllStateDirty();
@@ -379,6 +363,9 @@ void Renderer9::initializeDevice()
ASSERT(!mVertexDataManager && !mIndexDataManager);
mVertexDataManager = new VertexDataManager(this);
mIndexDataManager = new IndexDataManager(this, getRendererClass());
+
+ // TODO(jmadill): use context caps, and place in common D3D location
+ mTranslatedAttribCache.resize(getRendererCaps().maxVertexAttributes);
}
D3DPRESENT_PARAMETERS Renderer9::getDefaultPresentParameters()
@@ -523,6 +510,31 @@ egl::ConfigSet Renderer9::generateConfigs() const
return configs;
}
+void Renderer9::generateDisplayExtensions(egl::DisplayExtensions *outExtensions) const
+{
+ outExtensions->createContextRobustness = true;
+
+ if (getShareHandleSupport())
+ {
+ outExtensions->d3dShareHandleClientBuffer = true;
+ outExtensions->surfaceD3DTexture2DShareHandle = true;
+ }
+
+ outExtensions->querySurfacePointer = true;
+ outExtensions->windowFixedSize = true;
+ outExtensions->postSubBuffer = true;
+ outExtensions->createContext = true;
+ outExtensions->deviceQuery = true;
+ outExtensions->createContextNoError = true;
+
+ outExtensions->image = true;
+ outExtensions->imageBase = true;
+ outExtensions->glTexture2DImage = true;
+ outExtensions->glRenderbufferImage = true;
+
+ outExtensions->flexibleSurfaceCompatibility = true;
+}
+
void Renderer9::startScene()
{
if (!mSceneStarted)
@@ -612,7 +624,7 @@ gl::Error Renderer9::finish()
while (result == S_FALSE)
{
// Keep polling, but allow other threads to do something useful first
- Sleep(0);
+ ScheduleYield();
result = query->GetData(NULL, 0, D3DGETDATA_FLUSH);
@@ -642,9 +654,24 @@ gl::Error Renderer9::finish()
return gl::Error(GL_NO_ERROR);
}
-SwapChainD3D *Renderer9::createSwapChain(NativeWindow nativeWindow, HANDLE shareHandle, GLenum backBufferFormat, GLenum depthBufferFormat)
+SwapChainD3D *Renderer9::createSwapChain(NativeWindow nativeWindow,
+ HANDLE shareHandle,
+ GLenum backBufferFormat,
+ GLenum depthBufferFormat,
+ EGLint orientation)
+{
+ return new SwapChain9(this, nativeWindow, shareHandle, backBufferFormat, depthBufferFormat,
+ orientation);
+}
+
+CompilerImpl *Renderer9::createCompiler()
+{
+ return new CompilerD3D(SH_HLSL_3_0_OUTPUT);
+}
+
+void *Renderer9::getD3DDevice()
{
- return new SwapChain9(this, nativeWindow, shareHandle, backBufferFormat, depthBufferFormat);
+ return reinterpret_cast<void*>(mDevice);
}
gl::Error Renderer9::allocateEventQuery(IDirect3DQuery9 **outQuery)
@@ -716,9 +743,9 @@ BufferImpl *Renderer9::createBuffer()
return new Buffer9(this);
}
-VertexArrayImpl *Renderer9::createVertexArray()
+VertexArrayImpl *Renderer9::createVertexArray(const gl::VertexArray::Data &data)
{
- return new VertexArray9(this);
+ return new VertexArray9(data);
}
QueryImpl *Renderer9::createQuery(GLenum type)
@@ -766,46 +793,52 @@ gl::Error Renderer9::generateSwizzle(gl::Texture *texture)
gl::Error Renderer9::setSamplerState(gl::SamplerType type, int index, gl::Texture *texture, const gl::SamplerState &samplerState)
{
- std::vector<bool> &forceSetSamplers = (type == gl::SAMPLER_PIXEL) ? mForceSetPixelSamplerStates : mForceSetVertexSamplerStates;
- std::vector<gl::SamplerState> &appliedSamplers = (type == gl::SAMPLER_PIXEL) ? mCurPixelSamplerStates: mCurVertexSamplerStates;
+ CurSamplerState &appliedSampler = (type == gl::SAMPLER_PIXEL) ? mCurPixelSamplerStates[index]
+ : mCurVertexSamplerStates[index];
- if (forceSetSamplers[index] || memcmp(&samplerState, &appliedSamplers[index], sizeof(gl::SamplerState)) != 0)
- {
- int d3dSamplerOffset = (type == gl::SAMPLER_PIXEL) ? 0 : D3DVERTEXTEXTURESAMPLER0;
- int d3dSampler = index + d3dSamplerOffset;
+ // Make sure to add the level offset for our tiny compressed texture workaround
+ TextureD3D *textureD3D = GetImplAs<TextureD3D>(texture);
- // Make sure to add the level offset for our tiny compressed texture workaround
- TextureD3D *textureD3D = GetImplAs<TextureD3D>(texture);
+ TextureStorage *storage = nullptr;
+ gl::Error error = textureD3D->getNativeTexture(&storage);
+ if (error.isError())
+ {
+ return error;
+ }
- TextureStorage *storage = nullptr;
- gl::Error error = textureD3D->getNativeTexture(&storage);
- if (error.isError())
- {
- return error;
- }
+ // Storage should exist, texture should be complete
+ ASSERT(storage);
- // Storage should exist, texture should be complete
- ASSERT(storage);
+ DWORD baseLevel = texture->getBaseLevel() + storage->getTopLevel();
- DWORD baseLevel = samplerState.baseLevel + storage->getTopLevel();
+ if (appliedSampler.forceSet || appliedSampler.baseLevel != baseLevel ||
+ memcmp(&samplerState, &appliedSampler, sizeof(gl::SamplerState)) != 0)
+ {
+ int d3dSamplerOffset = (type == gl::SAMPLER_PIXEL) ? 0 : D3DVERTEXTEXTURESAMPLER0;
+ int d3dSampler = index + d3dSamplerOffset;
mDevice->SetSamplerState(d3dSampler, D3DSAMP_ADDRESSU, gl_d3d9::ConvertTextureWrap(samplerState.wrapS));
mDevice->SetSamplerState(d3dSampler, D3DSAMP_ADDRESSV, gl_d3d9::ConvertTextureWrap(samplerState.wrapT));
mDevice->SetSamplerState(d3dSampler, D3DSAMP_MAGFILTER, gl_d3d9::ConvertMagFilter(samplerState.magFilter, samplerState.maxAnisotropy));
+
D3DTEXTUREFILTERTYPE d3dMinFilter, d3dMipFilter;
- gl_d3d9::ConvertMinFilter(samplerState.minFilter, &d3dMinFilter, &d3dMipFilter, samplerState.maxAnisotropy);
+ float lodBias;
+ gl_d3d9::ConvertMinFilter(samplerState.minFilter, &d3dMinFilter, &d3dMipFilter, &lodBias,
+ samplerState.maxAnisotropy, baseLevel);
mDevice->SetSamplerState(d3dSampler, D3DSAMP_MINFILTER, d3dMinFilter);
mDevice->SetSamplerState(d3dSampler, D3DSAMP_MIPFILTER, d3dMipFilter);
mDevice->SetSamplerState(d3dSampler, D3DSAMP_MAXMIPLEVEL, baseLevel);
+ mDevice->SetSamplerState(d3dSampler, D3DSAMP_MIPMAPLODBIAS, static_cast<DWORD>(lodBias));
if (getRendererExtensions().textureFilterAnisotropic)
{
mDevice->SetSamplerState(d3dSampler, D3DSAMP_MAXANISOTROPY, (DWORD)samplerState.maxAnisotropy);
}
}
- forceSetSamplers[index] = false;
- appliedSamplers[index] = samplerState;
+ appliedSampler.forceSet = false;
+ appliedSampler.samplerState = samplerState;
+ appliedSampler.baseLevel = baseLevel;
return gl::Error(GL_NO_ERROR);
}
@@ -815,10 +848,9 @@ gl::Error Renderer9::setTexture(gl::SamplerType type, int index, gl::Texture *te
int d3dSamplerOffset = (type == gl::SAMPLER_PIXEL) ? 0 : D3DVERTEXTEXTURESAMPLER0;
int d3dSampler = index + d3dSamplerOffset;
IDirect3DBaseTexture9 *d3dTexture = NULL;
- unsigned int serial = 0;
bool forceSetTexture = false;
- std::vector<unsigned int> &appliedSerials = (type == gl::SAMPLER_PIXEL) ? mCurPixelTextureSerials : mCurVertexTextureSerials;
+ std::vector<uintptr_t> &appliedTextures = (type == gl::SAMPLER_PIXEL) ? mCurPixelTextures : mCurVertexTextures;
if (texture)
{
@@ -834,7 +866,7 @@ gl::Error Renderer9::setTexture(gl::SamplerType type, int index, gl::Texture *te
// Texture should be complete and have a storage
ASSERT(texStorage);
- TextureStorage9 *storage9 = TextureStorage9::makeTextureStorage9(texStorage);
+ TextureStorage9 *storage9 = GetAs<TextureStorage9>(texStorage);
error = storage9->getBaseTexture(&d3dTexture);
if (error.isError())
{
@@ -845,372 +877,99 @@ gl::Error Renderer9::setTexture(gl::SamplerType type, int index, gl::Texture *te
// in the texture class and we're unexpectedly missing the d3d texture
ASSERT(d3dTexture != NULL);
- serial = texture->getTextureSerial();
forceSetTexture = textureImpl->hasDirtyImages();
textureImpl->resetDirty();
}
- if (forceSetTexture || appliedSerials[index] != serial)
+ if (forceSetTexture || appliedTextures[index] != reinterpret_cast<uintptr_t>(d3dTexture))
{
mDevice->SetTexture(d3dSampler, d3dTexture);
}
- appliedSerials[index] = serial;
+ appliedTextures[index] = reinterpret_cast<uintptr_t>(d3dTexture);
return gl::Error(GL_NO_ERROR);
}
gl::Error Renderer9::setUniformBuffers(const gl::Data &/*data*/,
- const GLint /*vertexUniformBuffers*/[],
- const GLint /*fragmentUniformBuffers*/[])
+ const std::vector<GLint> &/*vertexUniformBuffers*/,
+ const std::vector<GLint> &/*fragmentUniformBuffers*/)
{
// No effect in ES2/D3D9
return gl::Error(GL_NO_ERROR);
}
-gl::Error Renderer9::setRasterizerState(const gl::RasterizerState &rasterState)
+void Renderer9::syncState(const gl::State &state, const gl::State::DirtyBits &bitmask)
{
- bool rasterStateChanged = mForceSetRasterState || memcmp(&rasterState, &mCurRasterState, sizeof(gl::RasterizerState)) != 0;
-
- if (rasterStateChanged)
- {
- // Set the cull mode
- if (rasterState.cullFace)
- {
- mDevice->SetRenderState(D3DRS_CULLMODE, gl_d3d9::ConvertCullMode(rasterState.cullMode, rasterState.frontFace));
- }
- else
- {
- mDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
- }
-
- if (rasterState.polygonOffsetFill)
- {
- if (mCurDepthSize > 0)
- {
- mDevice->SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS, *(DWORD*)&rasterState.polygonOffsetFactor);
-
- float depthBias = ldexp(rasterState.polygonOffsetUnits, -static_cast<int>(mCurDepthSize));
- mDevice->SetRenderState(D3DRS_DEPTHBIAS, *(DWORD*)&depthBias);
- }
- }
- else
- {
- mDevice->SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS, 0);
- mDevice->SetRenderState(D3DRS_DEPTHBIAS, 0);
- }
-
- mCurRasterState = rasterState;
- }
-
- mForceSetRasterState = false;
-
- return gl::Error(GL_NO_ERROR);
+ mStateManager.syncState(state, bitmask);
}
-gl::Error Renderer9::setBlendState(const gl::Framebuffer *framebuffer, const gl::BlendState &blendState, const gl::ColorF &blendColor,
- unsigned int sampleMask)
+gl::Error Renderer9::updateState(const gl::Data &data, GLenum drawMode)
{
- bool blendStateChanged = mForceSetBlendState || memcmp(&blendState, &mCurBlendState, sizeof(gl::BlendState)) != 0;
- bool blendColorChanged = mForceSetBlendState || memcmp(&blendColor, &mCurBlendColor, sizeof(gl::ColorF)) != 0;
- bool sampleMaskChanged = mForceSetBlendState || sampleMask != mCurSampleMask;
-
- if (blendStateChanged || blendColorChanged)
- {
- if (blendState.blend)
- {
- mDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
-
- if (blendState.sourceBlendRGB != GL_CONSTANT_ALPHA && blendState.sourceBlendRGB != GL_ONE_MINUS_CONSTANT_ALPHA &&
- blendState.destBlendRGB != GL_CONSTANT_ALPHA && blendState.destBlendRGB != GL_ONE_MINUS_CONSTANT_ALPHA)
- {
- mDevice->SetRenderState(D3DRS_BLENDFACTOR, gl_d3d9::ConvertColor(blendColor));
- }
- else
- {
- mDevice->SetRenderState(D3DRS_BLENDFACTOR, D3DCOLOR_RGBA(gl::unorm<8>(blendColor.alpha),
- gl::unorm<8>(blendColor.alpha),
- gl::unorm<8>(blendColor.alpha),
- gl::unorm<8>(blendColor.alpha)));
- }
-
- mDevice->SetRenderState(D3DRS_SRCBLEND, gl_d3d9::ConvertBlendFunc(blendState.sourceBlendRGB));
- mDevice->SetRenderState(D3DRS_DESTBLEND, gl_d3d9::ConvertBlendFunc(blendState.destBlendRGB));
- mDevice->SetRenderState(D3DRS_BLENDOP, gl_d3d9::ConvertBlendOp(blendState.blendEquationRGB));
-
- if (blendState.sourceBlendRGB != blendState.sourceBlendAlpha ||
- blendState.destBlendRGB != blendState.destBlendAlpha ||
- blendState.blendEquationRGB != blendState.blendEquationAlpha)
- {
- mDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE);
-
- mDevice->SetRenderState(D3DRS_SRCBLENDALPHA, gl_d3d9::ConvertBlendFunc(blendState.sourceBlendAlpha));
- mDevice->SetRenderState(D3DRS_DESTBLENDALPHA, gl_d3d9::ConvertBlendFunc(blendState.destBlendAlpha));
- mDevice->SetRenderState(D3DRS_BLENDOPALPHA, gl_d3d9::ConvertBlendOp(blendState.blendEquationAlpha));
- }
- else
- {
- mDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, FALSE);
- }
- }
- else
- {
- mDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
- }
-
- if (blendState.sampleAlphaToCoverage)
- {
- FIXME("Sample alpha to coverage is unimplemented.");
- }
-
- gl::FramebufferAttachment *attachment = framebuffer->getFirstColorbuffer();
- GLenum internalFormat = attachment ? attachment->getInternalFormat() : GL_NONE;
+ // Applies the render target surface, depth stencil surface, viewport rectangle and
+ // scissor rectangle to the renderer
+ const gl::Framebuffer *framebufferObject = data.state->getDrawFramebuffer();
+ ASSERT(framebufferObject && framebufferObject->checkStatus(data) == GL_FRAMEBUFFER_COMPLETE);
- // Set the color mask
- bool zeroColorMaskAllowed = getVendorId() != VENDOR_ID_AMD;
- // Apparently some ATI cards have a bug where a draw with a zero color
- // write mask can cause later draws to have incorrect results. Instead,
- // set a nonzero color write mask but modify the blend state so that no
- // drawing is done.
- // http://code.google.com/p/angleproject/issues/detail?id=169
-
- const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat);
- DWORD colorMask = gl_d3d9::ConvertColorMask(formatInfo.redBits > 0 && blendState.colorMaskRed,
- formatInfo.greenBits > 0 && blendState.colorMaskGreen,
- formatInfo.blueBits > 0 && blendState.colorMaskBlue,
- formatInfo.alphaBits > 0 && blendState.colorMaskAlpha);
- if (colorMask == 0 && !zeroColorMaskAllowed)
- {
- // Enable green channel, but set blending so nothing will be drawn.
- mDevice->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_GREEN);
- mDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
-
- mDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ZERO);
- mDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);
- mDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
- }
- else
- {
- mDevice->SetRenderState(D3DRS_COLORWRITEENABLE, colorMask);
- }
-
- mDevice->SetRenderState(D3DRS_DITHERENABLE, blendState.dither ? TRUE : FALSE);
-
- mCurBlendState = blendState;
- mCurBlendColor = blendColor;
- }
-
- if (sampleMaskChanged)
+ gl::Error error = applyRenderTarget(framebufferObject);
+ if (error.isError())
{
- // Set the multisample mask
- mDevice->SetRenderState(D3DRS_MULTISAMPLEANTIALIAS, TRUE);
- mDevice->SetRenderState(D3DRS_MULTISAMPLEMASK, static_cast<DWORD>(sampleMask));
-
- mCurSampleMask = sampleMask;
+ return error;
}
- mForceSetBlendState = false;
+ // Setting viewport state
+ setViewport(data.caps, data.state->getViewport(), data.state->getNearPlane(),
+ data.state->getFarPlane(), drawMode, data.state->getRasterizerState().frontFace,
+ false);
- return gl::Error(GL_NO_ERROR);
-}
+ // Setting scissors state
+ setScissorRectangle(data.state->getScissor(), data.state->isScissorTestEnabled());
-gl::Error Renderer9::setDepthStencilState(const gl::DepthStencilState &depthStencilState, int stencilRef,
- int stencilBackRef, bool frontFaceCCW)
-{
- bool depthStencilStateChanged = mForceSetDepthStencilState ||
- memcmp(&depthStencilState, &mCurDepthStencilState, sizeof(gl::DepthStencilState)) != 0;
- bool stencilRefChanged = mForceSetDepthStencilState || stencilRef != mCurStencilRef ||
- stencilBackRef != mCurStencilBackRef;
- bool frontFaceCCWChanged = mForceSetDepthStencilState || frontFaceCCW != mCurFrontFaceCCW;
+ // Setting blend, depth stencil, and rasterizer states
+ int samples = framebufferObject->getSamples(data);
+ gl::RasterizerState rasterizer = data.state->getRasterizerState();
+ rasterizer.pointDrawMode = (drawMode == GL_POINTS);
+ rasterizer.multiSample = (samples != 0);
- if (depthStencilStateChanged)
- {
- if (depthStencilState.depthTest)
- {
- mDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE);
- mDevice->SetRenderState(D3DRS_ZFUNC, gl_d3d9::ConvertComparison(depthStencilState.depthFunc));
- }
- else
- {
- mDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE);
- }
+ unsigned int mask = GetBlendSampleMask(data, samples);
+ error = setBlendDepthRasterStates(data, mask);
- mCurDepthStencilState = depthStencilState;
- }
-
- if (depthStencilStateChanged || stencilRefChanged || frontFaceCCWChanged)
+ if (error.isError())
{
- if (depthStencilState.stencilTest && mCurStencilSize > 0)
- {
- mDevice->SetRenderState(D3DRS_STENCILENABLE, TRUE);
- mDevice->SetRenderState(D3DRS_TWOSIDEDSTENCILMODE, TRUE);
-
- // FIXME: Unsupported by D3D9
- const D3DRENDERSTATETYPE D3DRS_CCW_STENCILREF = D3DRS_STENCILREF;
- const D3DRENDERSTATETYPE D3DRS_CCW_STENCILMASK = D3DRS_STENCILMASK;
- const D3DRENDERSTATETYPE D3DRS_CCW_STENCILWRITEMASK = D3DRS_STENCILWRITEMASK;
-
- ASSERT(depthStencilState.stencilWritemask == depthStencilState.stencilBackWritemask);
- ASSERT(stencilRef == stencilBackRef);
- ASSERT(depthStencilState.stencilMask == depthStencilState.stencilBackMask);
-
- // get the maximum size of the stencil ref
- unsigned int maxStencil = (1 << mCurStencilSize) - 1;
-
- mDevice->SetRenderState(frontFaceCCW ? D3DRS_STENCILWRITEMASK : D3DRS_CCW_STENCILWRITEMASK,
- depthStencilState.stencilWritemask);
- mDevice->SetRenderState(frontFaceCCW ? D3DRS_STENCILFUNC : D3DRS_CCW_STENCILFUNC,
- gl_d3d9::ConvertComparison(depthStencilState.stencilFunc));
-
- mDevice->SetRenderState(frontFaceCCW ? D3DRS_STENCILREF : D3DRS_CCW_STENCILREF,
- (stencilRef < (int)maxStencil) ? stencilRef : maxStencil);
- mDevice->SetRenderState(frontFaceCCW ? D3DRS_STENCILMASK : D3DRS_CCW_STENCILMASK,
- depthStencilState.stencilMask);
-
- mDevice->SetRenderState(frontFaceCCW ? D3DRS_STENCILFAIL : D3DRS_CCW_STENCILFAIL,
- gl_d3d9::ConvertStencilOp(depthStencilState.stencilFail));
- mDevice->SetRenderState(frontFaceCCW ? D3DRS_STENCILZFAIL : D3DRS_CCW_STENCILZFAIL,
- gl_d3d9::ConvertStencilOp(depthStencilState.stencilPassDepthFail));
- mDevice->SetRenderState(frontFaceCCW ? D3DRS_STENCILPASS : D3DRS_CCW_STENCILPASS,
- gl_d3d9::ConvertStencilOp(depthStencilState.stencilPassDepthPass));
-
- mDevice->SetRenderState(!frontFaceCCW ? D3DRS_STENCILWRITEMASK : D3DRS_CCW_STENCILWRITEMASK,
- depthStencilState.stencilBackWritemask);
- mDevice->SetRenderState(!frontFaceCCW ? D3DRS_STENCILFUNC : D3DRS_CCW_STENCILFUNC,
- gl_d3d9::ConvertComparison(depthStencilState.stencilBackFunc));
-
- mDevice->SetRenderState(!frontFaceCCW ? D3DRS_STENCILREF : D3DRS_CCW_STENCILREF,
- (stencilBackRef < (int)maxStencil) ? stencilBackRef : maxStencil);
- mDevice->SetRenderState(!frontFaceCCW ? D3DRS_STENCILMASK : D3DRS_CCW_STENCILMASK,
- depthStencilState.stencilBackMask);
-
- mDevice->SetRenderState(!frontFaceCCW ? D3DRS_STENCILFAIL : D3DRS_CCW_STENCILFAIL,
- gl_d3d9::ConvertStencilOp(depthStencilState.stencilBackFail));
- mDevice->SetRenderState(!frontFaceCCW ? D3DRS_STENCILZFAIL : D3DRS_CCW_STENCILZFAIL,
- gl_d3d9::ConvertStencilOp(depthStencilState.stencilBackPassDepthFail));
- mDevice->SetRenderState(!frontFaceCCW ? D3DRS_STENCILPASS : D3DRS_CCW_STENCILPASS,
- gl_d3d9::ConvertStencilOp(depthStencilState.stencilBackPassDepthPass));
- }
- else
- {
- mDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE);
- }
-
- mDevice->SetRenderState(D3DRS_ZWRITEENABLE, depthStencilState.depthMask ? TRUE : FALSE);
-
- mCurStencilRef = stencilRef;
- mCurStencilBackRef = stencilBackRef;
- mCurFrontFaceCCW = frontFaceCCW;
+ return error;
}
- mForceSetDepthStencilState = false;
+ mStateManager.resetDirtyBits();
- return gl::Error(GL_NO_ERROR);
+ return error;
}
void Renderer9::setScissorRectangle(const gl::Rectangle &scissor, bool enabled)
{
- bool scissorChanged = mForceSetScissor ||
- memcmp(&scissor, &mCurScissor, sizeof(gl::Rectangle)) != 0 ||
- enabled != mScissorEnabled;
-
- if (scissorChanged)
- {
- if (enabled)
- {
- RECT rect;
- rect.left = gl::clamp(scissor.x, 0, static_cast<int>(mRenderTargetDesc.width));
- rect.top = gl::clamp(scissor.y, 0, static_cast<int>(mRenderTargetDesc.height));
- rect.right = gl::clamp(scissor.x + scissor.width, 0, static_cast<int>(mRenderTargetDesc.width));
- rect.bottom = gl::clamp(scissor.y + scissor.height, 0, static_cast<int>(mRenderTargetDesc.height));
- mDevice->SetScissorRect(&rect);
- }
-
- mDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, enabled ? TRUE : FALSE);
+ mStateManager.setScissorState(scissor, enabled);
+}
- mScissorEnabled = enabled;
- mCurScissor = scissor;
- }
+gl::Error Renderer9::setBlendDepthRasterStates(const gl::Data &glData, GLenum drawMode)
+{
+ int samples = glData.state->getDrawFramebuffer()->getSamples(glData);
+ gl::RasterizerState rasterizer = glData.state->getRasterizerState();
+ rasterizer.pointDrawMode = (drawMode == GL_POINTS);
+ rasterizer.multiSample = (samples != 0);
- mForceSetScissor = false;
+ unsigned int mask = GetBlendSampleMask(glData, samples);
+ return mStateManager.setBlendDepthRasterStates(*glData.state, mask);
}
-void Renderer9::setViewport(const gl::Rectangle &viewport, float zNear, float zFar, GLenum drawMode, GLenum frontFace,
+void Renderer9::setViewport(const gl::Caps *caps,
+ const gl::Rectangle &viewport,
+ float zNear,
+ float zFar,
+ GLenum drawMode,
+ GLenum frontFace,
bool ignoreViewport)
{
- gl::Rectangle actualViewport = viewport;
- float actualZNear = gl::clamp01(zNear);
- float actualZFar = gl::clamp01(zFar);
- if (ignoreViewport)
- {
- actualViewport.x = 0;
- actualViewport.y = 0;
- actualViewport.width = mRenderTargetDesc.width;
- actualViewport.height = mRenderTargetDesc.height;
- actualZNear = 0.0f;
- actualZFar = 1.0f;
- }
-
- D3DVIEWPORT9 dxViewport;
- dxViewport.X = gl::clamp(actualViewport.x, 0, static_cast<int>(mRenderTargetDesc.width));
- dxViewport.Y = gl::clamp(actualViewport.y, 0, static_cast<int>(mRenderTargetDesc.height));
- dxViewport.Width = gl::clamp(actualViewport.width, 0, static_cast<int>(mRenderTargetDesc.width) - static_cast<int>(dxViewport.X));
- dxViewport.Height = gl::clamp(actualViewport.height, 0, static_cast<int>(mRenderTargetDesc.height) - static_cast<int>(dxViewport.Y));
- dxViewport.MinZ = actualZNear;
- dxViewport.MaxZ = actualZFar;
-
- float depthFront = !gl::IsTriangleMode(drawMode) ? 0.0f : (frontFace == GL_CCW ? 1.0f : -1.0f);
-
- bool viewportChanged = mForceSetViewport || memcmp(&actualViewport, &mCurViewport, sizeof(gl::Rectangle)) != 0 ||
- actualZNear != mCurNear || actualZFar != mCurFar || mCurDepthFront != depthFront;
- if (viewportChanged)
- {
- mDevice->SetViewport(&dxViewport);
-
- mCurViewport = actualViewport;
- mCurNear = actualZNear;
- mCurFar = actualZFar;
- mCurDepthFront = depthFront;
-
- dx_VertexConstants vc = {0};
- dx_PixelConstants pc = {0};
-
- vc.viewAdjust[0] = (float)((actualViewport.width - (int)dxViewport.Width) + 2 * (actualViewport.x - (int)dxViewport.X) - 1) / dxViewport.Width;
- vc.viewAdjust[1] = (float)((actualViewport.height - (int)dxViewport.Height) + 2 * (actualViewport.y - (int)dxViewport.Y) - 1) / dxViewport.Height;
- vc.viewAdjust[2] = (float)actualViewport.width / dxViewport.Width;
- vc.viewAdjust[3] = (float)actualViewport.height / dxViewport.Height;
-
- pc.viewCoords[0] = actualViewport.width * 0.5f;
- pc.viewCoords[1] = actualViewport.height * 0.5f;
- pc.viewCoords[2] = actualViewport.x + (actualViewport.width * 0.5f);
- pc.viewCoords[3] = actualViewport.y + (actualViewport.height * 0.5f);
-
- pc.depthFront[0] = (actualZFar - actualZNear) * 0.5f;
- pc.depthFront[1] = (actualZNear + actualZFar) * 0.5f;
- pc.depthFront[2] = depthFront;
-
- vc.depthRange[0] = actualZNear;
- vc.depthRange[1] = actualZFar;
- vc.depthRange[2] = actualZFar - actualZNear;
-
- pc.depthRange[0] = actualZNear;
- pc.depthRange[1] = actualZFar;
- pc.depthRange[2] = actualZFar - actualZNear;
-
- if (memcmp(&vc, &mVertexConstants, sizeof(dx_VertexConstants)) != 0)
- {
- mVertexConstants = vc;
- mDxUniformsDirty = true;
- }
-
- if (memcmp(&pc, &mPixelConstants, sizeof(dx_PixelConstants)) != 0)
- {
- mPixelConstants = pc;
- mDxUniformsDirty = true;
- }
- }
-
- mForceSetViewport = false;
+ mStateManager.setViewportState(caps, viewport, zNear, zFar, drawMode, frontFace,
+ ignoreViewport);
}
bool Renderer9::applyPrimitiveType(GLenum mode, GLsizei count, bool usesPointSize)
@@ -1258,15 +1017,14 @@ gl::Error Renderer9::getNullColorbuffer(const gl::FramebufferAttachment *depthbu
{
ASSERT(depthbuffer);
- GLsizei width = depthbuffer->getWidth();
- GLsizei height = depthbuffer->getHeight();
+ const gl::Extents &size = depthbuffer->getSize();
// search cached nullcolorbuffers
for (int i = 0; i < NUM_NULL_COLORBUFFER_CACHE_ENTRIES; i++)
{
if (mNullColorbufferCache[i].buffer != NULL &&
- mNullColorbufferCache[i].width == width &&
- mNullColorbufferCache[i].height == height)
+ mNullColorbufferCache[i].width == size.width &&
+ mNullColorbufferCache[i].height == size.height)
{
mNullColorbufferCache[i].lruCount = ++mMaxNullColorbufferLRU;
*outColorBuffer = mNullColorbufferCache[i].buffer;
@@ -1275,14 +1033,14 @@ gl::Error Renderer9::getNullColorbuffer(const gl::FramebufferAttachment *depthbu
}
gl::Renderbuffer *nullRenderbuffer = new gl::Renderbuffer(createRenderbuffer(), 0);
- gl::Error error = nullRenderbuffer->setStorage(GL_NONE, width, height);
+ gl::Error error = nullRenderbuffer->setStorage(GL_NONE, size.width, size.height);
if (error.isError())
{
SafeDelete(nullRenderbuffer);
return error;
}
- gl::RenderbufferAttachment *nullbuffer = new gl::RenderbufferAttachment(GL_NONE, nullRenderbuffer);
+ gl::FramebufferAttachment *nullbuffer = new gl::FramebufferAttachment(GL_RENDERBUFFER, GL_NONE, gl::ImageIndex::MakeInvalid(), nullRenderbuffer);
// add nullbuffer to the cache
NullColorbufferCacheEntry *oldest = &mNullColorbufferCache[0];
@@ -1297,44 +1055,48 @@ gl::Error Renderer9::getNullColorbuffer(const gl::FramebufferAttachment *depthbu
delete oldest->buffer;
oldest->buffer = nullbuffer;
oldest->lruCount = ++mMaxNullColorbufferLRU;
- oldest->width = width;
- oldest->height = height;
+ oldest->width = size.width;
+ oldest->height = size.height;
*outColorBuffer = nullbuffer;
return gl::Error(GL_NO_ERROR);
}
-gl::Error Renderer9::applyRenderTarget(const gl::FramebufferAttachment *colorBuffer, const gl::FramebufferAttachment *depthStencilBuffer)
+gl::Error Renderer9::applyRenderTarget(const gl::FramebufferAttachment *colorAttachment,
+ const gl::FramebufferAttachment *depthStencilAttachment)
{
+ const gl::FramebufferAttachment *renderAttachment = colorAttachment;
+ gl::Error error(GL_NO_ERROR);
+
// if there is no color attachment we must synthesize a NULL colorattachment
// to keep the D3D runtime happy. This should only be possible if depth texturing.
- if (!colorBuffer)
+ if (renderAttachment == nullptr)
{
- gl::Error error = getNullColorbuffer(depthStencilBuffer, &colorBuffer);
+ error = getNullColorbuffer(depthStencilAttachment, &renderAttachment);
if (error.isError())
{
return error;
}
}
- ASSERT(colorBuffer);
+ ASSERT(renderAttachment != nullptr);
size_t renderTargetWidth = 0;
size_t renderTargetHeight = 0;
D3DFORMAT renderTargetFormat = D3DFMT_UNKNOWN;
+ RenderTarget9 *renderTarget = nullptr;
+ error = renderAttachment->getRenderTarget(&renderTarget);
+ if (error.isError())
+ {
+ return error;
+ }
+ ASSERT(renderTarget);
+
bool renderTargetChanged = false;
- unsigned int renderTargetSerial = GetAttachmentSerial(colorBuffer);
+ unsigned int renderTargetSerial = renderTarget->getSerial();
if (renderTargetSerial != mAppliedRenderTargetSerial)
{
// Apply the render target on the device
- RenderTarget9 *renderTarget = NULL;
- gl::Error error = d3d9::GetAttachmentRenderTarget(colorBuffer, &renderTarget);
- if (error.isError())
- {
- return error;
- }
- ASSERT(renderTarget);
-
IDirect3DSurface9 *renderTargetSurface = renderTarget->getSurface();
ASSERT(renderTargetSurface);
@@ -1349,48 +1111,45 @@ gl::Error Renderer9::applyRenderTarget(const gl::FramebufferAttachment *colorBuf
renderTargetChanged = true;
}
- unsigned int depthStencilSerial = (depthStencilBuffer != nullptr) ? GetAttachmentSerial(depthStencilBuffer) : 0;
+ RenderTarget9 *depthStencilRenderTarget = nullptr;
+ unsigned int depthStencilSerial = 0;
+
+ if (depthStencilAttachment != nullptr)
+ {
+ error = depthStencilAttachment->getRenderTarget(&depthStencilRenderTarget);
+ if (error.isError())
+ {
+ return error;
+ }
+ ASSERT(depthStencilRenderTarget);
+
+ depthStencilSerial = depthStencilRenderTarget->getSerial();
+ }
+
if (depthStencilSerial != mAppliedDepthStencilSerial || !mDepthStencilInitialized)
{
unsigned int depthSize = 0;
unsigned int stencilSize = 0;
// Apply the depth stencil on the device
- if (depthStencilBuffer)
+ if (depthStencilRenderTarget)
{
- RenderTarget9 *depthStencilRenderTarget = NULL;
- gl::Error error = d3d9::GetAttachmentRenderTarget(depthStencilBuffer, &depthStencilRenderTarget);
- if (error.isError())
- {
- return error;
- }
- ASSERT(depthStencilRenderTarget);
-
IDirect3DSurface9 *depthStencilSurface = depthStencilRenderTarget->getSurface();
ASSERT(depthStencilSurface);
mDevice->SetDepthStencilSurface(depthStencilSurface);
SafeRelease(depthStencilSurface);
- depthSize = depthStencilBuffer->getDepthSize();
- stencilSize = depthStencilBuffer->getStencilSize();
+ depthSize = depthStencilAttachment->getDepthSize();
+ stencilSize = depthStencilAttachment->getStencilSize();
}
else
{
mDevice->SetDepthStencilSurface(NULL);
}
- if (!mDepthStencilInitialized || depthSize != mCurDepthSize)
- {
- mCurDepthSize = depthSize;
- mForceSetRasterState = true;
- }
-
- if (!mDepthStencilInitialized || stencilSize != mCurStencilSize)
- {
- mCurStencilSize = stencilSize;
- mForceSetDepthStencilState = true;
- }
+ mStateManager.updateDepthSizeIfChanged(mDepthStencilInitialized, depthSize);
+ mStateManager.updateStencilSizeIfChanged(mDepthStencilInitialized, stencilSize);
mAppliedDepthStencilSerial = depthStencilSerial;
mDepthStencilInitialized = true;
@@ -1398,13 +1157,9 @@ gl::Error Renderer9::applyRenderTarget(const gl::FramebufferAttachment *colorBuf
if (renderTargetChanged || !mRenderTargetDescInitialized)
{
- mForceSetScissor = true;
- mForceSetViewport = true;
- mForceSetBlendState = true;
-
- mRenderTargetDesc.width = renderTargetWidth;
- mRenderTargetDesc.height = renderTargetHeight;
- mRenderTargetDesc.format = renderTargetFormat;
+ mStateManager.forceSetBlendState();
+ mStateManager.forceSetScissorState();
+ mStateManager.setRenderTargetBounds(renderTargetWidth, renderTargetHeight);
mRenderTargetDescInitialized = true;
}
@@ -1416,22 +1171,34 @@ gl::Error Renderer9::applyRenderTarget(const gl::Framebuffer *framebuffer)
return applyRenderTarget(framebuffer->getColorbuffer(0), framebuffer->getDepthOrStencilbuffer());
}
-gl::Error Renderer9::applyVertexBuffer(const gl::State &state, GLenum mode, GLint first, GLsizei count, GLsizei instances)
+gl::Error Renderer9::applyVertexBuffer(const gl::State &state,
+ GLenum mode,
+ GLint first,
+ GLsizei count,
+ GLsizei instances,
+ TranslatedIndexData * /*indexInfo*/)
{
- TranslatedAttribute attributes[gl::MAX_VERTEX_ATTRIBS];
- gl::Error error = mVertexDataManager->prepareVertexData(state, first, count, attributes, instances);
+ gl::Error error = mVertexDataManager->prepareVertexData(state, first, count, &mTranslatedAttribCache, instances);
if (error.isError())
{
return error;
}
- return mVertexDeclarationCache.applyDeclaration(mDevice, attributes, state.getProgram(), instances, &mRepeatDraw);
+ return mVertexDeclarationCache.applyDeclaration(mDevice, mTranslatedAttribCache, state.getProgram(), instances, &mRepeatDraw);
}
// Applies the indices and element array bindings to the Direct3D 9 device
-gl::Error Renderer9::applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo)
-{
- gl::Error error = mIndexDataManager->prepareIndexData(type, count, elementArrayBuffer, indices, indexInfo);
+gl::Error Renderer9::applyIndexBuffer(const gl::Data &data,
+ const GLvoid *indices,
+ GLsizei count,
+ GLenum mode,
+ GLenum type,
+ TranslatedIndexData *indexInfo)
+{
+ gl::VertexArray *vao = data.state->getVertexArray();
+ gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
+ gl::Error error = mIndexDataManager->prepareIndexData(type, count, elementArrayBuffer, indices,
+ indexInfo, false);
if (error.isError())
{
return error;
@@ -1442,7 +1209,7 @@ gl::Error Renderer9::applyIndexBuffer(const GLvoid *indices, gl::Buffer *element
if (indexInfo->serial != mAppliedIBSerial)
{
- IndexBuffer9* indexBuffer = IndexBuffer9::makeIndexBuffer9(indexInfo->indexBuffer);
+ IndexBuffer9* indexBuffer = GetAs<IndexBuffer9>(indexInfo->indexBuffer);
mDevice->SetIndices(indexBuffer->getBuffer());
mAppliedIBSerial = indexInfo->serial;
@@ -1456,7 +1223,10 @@ void Renderer9::applyTransformFeedbackBuffers(const gl::State& state)
ASSERT(!state.isTransformFeedbackActiveUnpaused());
}
-gl::Error Renderer9::drawArrays(const gl::Data &data, GLenum mode, GLsizei count, GLsizei instances, bool usesPointSize)
+gl::Error Renderer9::drawArraysImpl(const gl::Data &data,
+ GLenum mode,
+ GLsizei count,
+ GLsizei instances)
{
ASSERT(!data.state->isTransformFeedbackActiveUnpaused());
@@ -1477,7 +1247,7 @@ gl::Error Renderer9::drawArrays(const gl::Data &data, GLenum mode, GLsizei count
if (mAppliedIBSerial != countingIB->getSerial())
{
- IndexBuffer9 *indexBuffer = IndexBuffer9::makeIndexBuffer9(countingIB->getIndexBuffer());
+ IndexBuffer9 *indexBuffer = GetAs<IndexBuffer9>(countingIB->getIndexBuffer());
mDevice->SetIndices(indexBuffer->getBuffer());
mAppliedIBSerial = countingIB->getSerial();
@@ -1497,13 +1267,21 @@ gl::Error Renderer9::drawArrays(const gl::Data &data, GLenum mode, GLsizei count
}
}
-gl::Error Renderer9::drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices,
- gl::Buffer *elementArrayBuffer, const TranslatedIndexData &indexInfo, GLsizei /*instances*/)
+gl::Error Renderer9::drawElementsImpl(const gl::Data &data,
+ const TranslatedIndexData &indexInfo,
+ GLenum mode,
+ GLsizei count,
+ GLenum type,
+ const GLvoid *indices,
+ GLsizei /*instances*/)
{
startScene();
int minIndex = static_cast<int>(indexInfo.indexRange.start);
+ gl::VertexArray *vao = data.state->getVertexArray();
+ gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
+
if (mode == GL_POINTS)
{
return drawIndexedPoints(count, type, indices, minIndex, elementArrayBuffer);
@@ -1514,10 +1292,12 @@ gl::Error Renderer9::drawElements(GLenum mode, GLsizei count, GLenum type, const
}
else
{
+ size_t vertexCount = indexInfo.indexRange.vertexCount();
for (int i = 0; i < mRepeatDraw; i++)
{
- GLsizei vertexCount = static_cast<int>(indexInfo.indexRange.length()) + 1;
- mDevice->DrawIndexedPrimitive(mPrimitiveType, -minIndex, minIndex, vertexCount, indexInfo.startIndex, mPrimitiveCount);
+ mDevice->DrawIndexedPrimitive(mPrimitiveType, -minIndex, minIndex,
+ static_cast<UINT>(vertexCount), indexInfo.startIndex,
+ mPrimitiveCount);
}
return gl::Error(GL_NO_ERROR);
}
@@ -1663,7 +1443,7 @@ gl::Error Renderer9::drawLineLoop(GLsizei count, GLenum type, const GLvoid *indi
case GL_NONE: // Non-indexed draw
for (int i = 0; i < count; i++)
{
- data[i] = i;
+ data[i] = static_cast<unsigned short>(i);
}
data[count] = 0;
break;
@@ -1684,9 +1464,9 @@ gl::Error Renderer9::drawLineLoop(GLsizei count, GLenum type, const GLvoid *indi
case GL_UNSIGNED_INT:
for (int i = 0; i < count; i++)
{
- data[i] = static_cast<const GLuint*>(indices)[i];
+ data[i] = static_cast<unsigned short>(static_cast<const GLuint*>(indices)[i]);
}
- data[count] = static_cast<const GLuint*>(indices)[0];
+ data[count] = static_cast<unsigned short>(static_cast<const GLuint*>(indices)[0]);
break;
default: UNREACHABLE();
}
@@ -1700,7 +1480,7 @@ gl::Error Renderer9::drawLineLoop(GLsizei count, GLenum type, const GLvoid *indi
if (mAppliedIBSerial != mLineLoopIB->getSerial())
{
- IndexBuffer9 *indexBuffer = IndexBuffer9::makeIndexBuffer9(mLineLoopIB->getIndexBuffer());
+ IndexBuffer9 *indexBuffer = GetAs<IndexBuffer9>(mLineLoopIB->getIndexBuffer());
mDevice->SetIndices(indexBuffer->getBuffer());
mAppliedIBSerial = mLineLoopIB->getSerial();
@@ -1757,7 +1537,7 @@ gl::Error Renderer9::getCountingIB(size_t count, StaticIndexBufferInterface **ou
// Update the counting index buffer if it is not large enough or has not been created yet.
if (count <= 65536) // 16-bit indices
{
- const unsigned int spaceNeeded = count * sizeof(unsigned short);
+ const unsigned int spaceNeeded = static_cast<unsigned int>(count) * sizeof(unsigned short);
if (!mCountingIB || mCountingIB->getBufferSize() < spaceNeeded)
{
@@ -1775,7 +1555,7 @@ gl::Error Renderer9::getCountingIB(size_t count, StaticIndexBufferInterface **ou
unsigned short *data = reinterpret_cast<unsigned short*>(mappedMemory);
for (size_t i = 0; i < count; i++)
{
- data[i] = i;
+ data[i] = static_cast<unsigned short>(i);
}
error = mCountingIB->unmapBuffer();
@@ -1787,7 +1567,7 @@ gl::Error Renderer9::getCountingIB(size_t count, StaticIndexBufferInterface **ou
}
else if (getRendererExtensions().elementIndexUint)
{
- const unsigned int spaceNeeded = count * sizeof(unsigned int);
+ const unsigned int spaceNeeded = static_cast<unsigned int>(count) * sizeof(unsigned int);
if (!mCountingIB || mCountingIB->getBufferSize() < spaceNeeded)
{
@@ -1803,7 +1583,7 @@ gl::Error Renderer9::getCountingIB(size_t count, StaticIndexBufferInterface **ou
}
unsigned int *data = reinterpret_cast<unsigned int*>(mappedMemory);
- for (size_t i = 0; i < count; i++)
+ for (unsigned int i = 0; i < count; i++)
{
data[i] = i;
}
@@ -1824,13 +1604,10 @@ gl::Error Renderer9::getCountingIB(size_t count, StaticIndexBufferInterface **ou
return gl::Error(GL_NO_ERROR);
}
-gl::Error Renderer9::applyShaders(gl::Program *program, const gl::VertexFormat inputLayout[], const gl::Framebuffer *framebuffer,
- bool rasterizerDiscard, bool transformFeedbackActive)
+gl::Error Renderer9::applyShadersImpl(const gl::Data &data, GLenum /*drawMode*/)
{
- ASSERT(!transformFeedbackActive);
- ASSERT(!rasterizerDiscard);
-
- ProgramD3D *programD3D = GetImplAs<ProgramD3D>(program);
+ ProgramD3D *programD3D = GetImplAs<ProgramD3D>(data.state->getProgram());
+ const auto &inputLayout = programD3D->getCachedInputLayout();
ShaderExecutableD3D *vertexExe = NULL;
gl::Error error = programD3D->getVertexExecutableForInputLayout(inputLayout, &vertexExe, nullptr);
@@ -1839,15 +1616,16 @@ gl::Error Renderer9::applyShaders(gl::Program *program, const gl::VertexFormat i
return error;
}
+ const gl::Framebuffer *drawFramebuffer = data.state->getDrawFramebuffer();
ShaderExecutableD3D *pixelExe = NULL;
- error = programD3D->getPixelExecutableForFramebuffer(framebuffer, &pixelExe);
+ error = programD3D->getPixelExecutableForFramebuffer(drawFramebuffer, &pixelExe);
if (error.isError())
{
return error;
}
- IDirect3DVertexShader9 *vertexShader = (vertexExe ? ShaderExecutable9::makeShaderExecutable9(vertexExe)->getVertexShader() : NULL);
- IDirect3DPixelShader9 *pixelShader = (pixelExe ? ShaderExecutable9::makeShaderExecutable9(pixelExe)->getPixelShader() : NULL);
+ IDirect3DVertexShader9 *vertexShader = (vertexExe ? GetAs<ShaderExecutable9>(vertexExe)->getVertexShader() : nullptr);
+ IDirect3DPixelShader9 *pixelShader = (pixelExe ? GetAs<ShaderExecutable9>(pixelExe)->getPixelShader() : nullptr);
if (vertexShader != mAppliedVertexShader)
{
@@ -1870,68 +1648,63 @@ gl::Error Renderer9::applyShaders(gl::Program *program, const gl::VertexFormat i
if (programSerial != mAppliedProgramSerial)
{
programD3D->dirtyAllUniforms();
- mDxUniformsDirty = true;
+ mStateManager.forceSetDXUniformsState();
mAppliedProgramSerial = programSerial;
}
return gl::Error(GL_NO_ERROR);
}
-gl::Error Renderer9::applyUniforms(const ProgramImpl &program, const std::vector<gl::LinkedUniform*> &uniformArray)
+gl::Error Renderer9::applyUniforms(const ProgramD3D &programD3D,
+ GLenum /*drawMode*/,
+ const std::vector<D3DUniform *> &uniformArray)
{
- for (size_t uniformIndex = 0; uniformIndex < uniformArray.size(); uniformIndex++)
+ for (const D3DUniform *targetUniform : uniformArray)
{
- gl::LinkedUniform *targetUniform = uniformArray[uniformIndex];
+ if (!targetUniform->dirty)
+ continue;
- if (targetUniform->dirty)
- {
- GLfloat *f = (GLfloat*)targetUniform->data;
- GLint *i = (GLint*)targetUniform->data;
+ GLfloat *f = (GLfloat *)targetUniform->data;
+ GLint *i = (GLint *)targetUniform->data;
- switch (targetUniform->type)
- {
- case GL_SAMPLER_2D:
- case GL_SAMPLER_CUBE:
+ switch (targetUniform->type)
+ {
+ case GL_SAMPLER_2D:
+ case GL_SAMPLER_CUBE:
break;
- case GL_BOOL:
- case GL_BOOL_VEC2:
- case GL_BOOL_VEC3:
- case GL_BOOL_VEC4:
+ case GL_BOOL:
+ case GL_BOOL_VEC2:
+ case GL_BOOL_VEC3:
+ case GL_BOOL_VEC4:
applyUniformnbv(targetUniform, i);
break;
- case GL_FLOAT:
- case GL_FLOAT_VEC2:
- case GL_FLOAT_VEC3:
- case GL_FLOAT_VEC4:
- case GL_FLOAT_MAT2:
- case GL_FLOAT_MAT3:
- case GL_FLOAT_MAT4:
+ case GL_FLOAT:
+ case GL_FLOAT_VEC2:
+ case GL_FLOAT_VEC3:
+ case GL_FLOAT_VEC4:
+ case GL_FLOAT_MAT2:
+ case GL_FLOAT_MAT3:
+ case GL_FLOAT_MAT4:
applyUniformnfv(targetUniform, f);
break;
- case GL_INT:
- case GL_INT_VEC2:
- case GL_INT_VEC3:
- case GL_INT_VEC4:
+ case GL_INT:
+ case GL_INT_VEC2:
+ case GL_INT_VEC3:
+ case GL_INT_VEC4:
applyUniformniv(targetUniform, i);
break;
- default:
+ default:
UNREACHABLE();
- }
}
}
// Driver uniforms
- if (mDxUniformsDirty)
- {
- mDevice->SetVertexShaderConstantF(0, (float*)&mVertexConstants, sizeof(dx_VertexConstants) / sizeof(float[4]));
- mDevice->SetPixelShaderConstantF(0, (float*)&mPixelConstants, sizeof(dx_PixelConstants) / sizeof(float[4]));
- mDxUniformsDirty = false;
- }
+ mStateManager.setShaderConstants();
return gl::Error(GL_NO_ERROR);
}
-void Renderer9::applyUniformnfv(gl::LinkedUniform *targetUniform, const GLfloat *v)
+void Renderer9::applyUniformnfv(const D3DUniform *targetUniform, const GLfloat *v)
{
if (targetUniform->isReferencedByFragmentShader())
{
@@ -1944,7 +1717,7 @@ void Renderer9::applyUniformnfv(gl::LinkedUniform *targetUniform, const GLfloat
}
}
-void Renderer9::applyUniformniv(gl::LinkedUniform *targetUniform, const GLint *v)
+void Renderer9::applyUniformniv(const D3DUniform *targetUniform, const GLint *v)
{
ASSERT(targetUniform->registerCount <= MAX_VERTEX_CONSTANT_VECTORS_D3D9);
GLfloat vector[MAX_VERTEX_CONSTANT_VECTORS_D3D9][4];
@@ -1960,7 +1733,7 @@ void Renderer9::applyUniformniv(gl::LinkedUniform *targetUniform, const GLint *v
applyUniformnfv(targetUniform, (GLfloat*)vector);
}
-void Renderer9::applyUniformnbv(gl::LinkedUniform *targetUniform, const GLint *v)
+void Renderer9::applyUniformnbv(const D3DUniform *targetUniform, const GLint *v)
{
ASSERT(targetUniform->registerCount <= MAX_VERTEX_CONSTANT_VECTORS_D3D9);
GLfloat vector[MAX_VERTEX_CONSTANT_VECTORS_D3D9][4];
@@ -2004,14 +1777,16 @@ gl::Error Renderer9::clear(const ClearParameters &clearParams,
unsigned int stencilUnmasked = 0x0;
if (clearParams.clearStencil && depthStencilBuffer->getStencilSize() > 0)
{
- RenderTargetD3D *stencilRenderTarget = NULL;
- gl::Error error = GetAttachmentRenderTarget(depthStencilBuffer, &stencilRenderTarget);
+ ASSERT(depthStencilBuffer != nullptr);
+
+ RenderTargetD3D *stencilRenderTarget = nullptr;
+ gl::Error error = depthStencilBuffer->getRenderTarget(&stencilRenderTarget);
if (error.isError())
{
return error;
}
- RenderTarget9 *stencilRenderTarget9 = RenderTarget9::makeRenderTarget9(stencilRenderTarget);
+ RenderTarget9 *stencilRenderTarget9 = GetAs<RenderTarget9>(stencilRenderTarget);
ASSERT(stencilRenderTarget9);
const d3d9::D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(stencilRenderTarget9->getD3DFormat());
@@ -2025,14 +1800,16 @@ gl::Error Renderer9::clear(const ClearParameters &clearParams,
D3DCOLOR color = D3DCOLOR_ARGB(255, 0, 0, 0);
if (clearColor)
{
+ ASSERT(colorBuffer != nullptr);
+
RenderTargetD3D *colorRenderTarget = NULL;
- gl::Error error = GetAttachmentRenderTarget(colorBuffer, &colorRenderTarget);
+ gl::Error error = colorBuffer->getRenderTarget(&colorRenderTarget);
if (error.isError())
{
return error;
}
- RenderTarget9 *colorRenderTarget9 = RenderTarget9::makeRenderTarget9(colorRenderTarget);
+ RenderTarget9 *colorRenderTarget9 = GetAs<RenderTarget9>(colorRenderTarget);
ASSERT(colorRenderTarget9);
const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(colorBuffer->getInternalFormat());
@@ -2156,14 +1933,17 @@ gl::Error Renderer9::clear(const ClearParameters &clearParams,
mDevice->SetStreamSourceFreq(i, 1);
}
+ int renderTargetWidth = mStateManager.getRenderTargetWidth();
+ int renderTargetHeight = mStateManager.getRenderTargetHeight();
+
float quad[4][4]; // A quadrilateral covering the target, aligned to match the edges
quad[0][0] = -0.5f;
- quad[0][1] = mRenderTargetDesc.height - 0.5f;
+ quad[0][1] = renderTargetHeight - 0.5f;
quad[0][2] = 0.0f;
quad[0][3] = 1.0f;
- quad[1][0] = mRenderTargetDesc.width - 0.5f;
- quad[1][1] = mRenderTargetDesc.height - 0.5f;
+ quad[1][0] = renderTargetWidth - 0.5f;
+ quad[1][1] = renderTargetHeight - 0.5f;
quad[1][2] = 0.0f;
quad[1][3] = 1.0f;
@@ -2172,7 +1952,7 @@ gl::Error Renderer9::clear(const ClearParameters &clearParams,
quad[2][2] = 0.0f;
quad[2][3] = 1.0f;
- quad[3][0] = mRenderTargetDesc.width - 0.5f;
+ quad[3][0] = renderTargetWidth - 0.5f;
quad[3][1] = -0.5f;
quad[3][2] = 0.0f;
quad[3][3] = 1.0f;
@@ -2221,31 +2001,31 @@ void Renderer9::markAllStateDirty()
mDepthStencilInitialized = false;
mRenderTargetDescInitialized = false;
- mForceSetDepthStencilState = true;
- mForceSetRasterState = true;
- mForceSetScissor = true;
- mForceSetViewport = true;
- mForceSetBlendState = true;
+ mStateManager.forceSetRasterState();
+ mStateManager.forceSetDepthStencilState();
+ mStateManager.forceSetBlendState();
+ mStateManager.forceSetScissorState();
+ mStateManager.forceSetViewportState();
- ASSERT(mForceSetVertexSamplerStates.size() == mCurVertexTextureSerials.size());
- for (unsigned int i = 0; i < mForceSetVertexSamplerStates.size(); i++)
+ ASSERT(mCurVertexSamplerStates.size() == mCurVertexTextures.size());
+ for (unsigned int i = 0; i < mCurVertexTextures.size(); i++)
{
- mForceSetVertexSamplerStates[i] = true;
- mCurVertexTextureSerials[i] = 0;
+ mCurVertexSamplerStates[i].forceSet = true;
+ mCurVertexTextures[i] = angle::DirtyPointer;
}
- ASSERT(mForceSetPixelSamplerStates.size() == mCurPixelTextureSerials.size());
- for (unsigned int i = 0; i < mForceSetPixelSamplerStates.size(); i++)
+ ASSERT(mCurPixelSamplerStates.size() == mCurPixelTextures.size());
+ for (unsigned int i = 0; i < mCurPixelSamplerStates.size(); i++)
{
- mForceSetPixelSamplerStates[i] = true;
- mCurPixelTextureSerials[i] = 0;
+ mCurPixelSamplerStates[i].forceSet = true;
+ mCurPixelTextures[i] = angle::DirtyPointer;
}
mAppliedIBSerial = 0;
mAppliedVertexShader = NULL;
mAppliedPixelShader = NULL;
mAppliedProgramSerial = 0;
- mDxUniformsDirty = true;
+ mStateManager.forceSetDXUniformsState();
mVertexDeclarationCache.markStateDirty();
}
@@ -2458,19 +2238,26 @@ std::string Renderer9::getRendererDescription() const
return rendererString.str();
}
-GUID Renderer9::getAdapterIdentifier() const
+DeviceIdentifier Renderer9::getAdapterIdentifier() const
{
- return mAdapterIdentifier.DeviceIdentifier;
+ DeviceIdentifier deviceIdentifier = { 0 };
+ deviceIdentifier.VendorId = static_cast<UINT>(mAdapterIdentifier.VendorId);
+ deviceIdentifier.DeviceId = static_cast<UINT>(mAdapterIdentifier.DeviceId);
+ deviceIdentifier.SubSysId = static_cast<UINT>(mAdapterIdentifier.SubSysId);
+ deviceIdentifier.Revision = static_cast<UINT>(mAdapterIdentifier.Revision);
+ deviceIdentifier.FeatureLevel = 0;
+
+ return deviceIdentifier;
}
unsigned int Renderer9::getReservedVertexUniformVectors() const
{
- return 2; // dx_ViewAdjust and dx_DepthRange.
+ return d3d9_gl::GetReservedVertexUniformVectors();
}
unsigned int Renderer9::getReservedFragmentUniformVectors() const
{
- return 3; // dx_ViewCoords, dx_DepthFront and dx_DepthRange.
+ return d3d9_gl::GetReservedFragmentUniformVectors();
}
unsigned int Renderer9::getReservedVertexUniformBuffers() const
@@ -2489,11 +2276,6 @@ bool Renderer9::getShareHandleSupport() const
return (mD3d9Ex != NULL) && !gl::DebugAnnotationsActive();
}
-bool Renderer9::getPostSubBufferSupport() const
-{
- return true;
-}
-
int Renderer9::getMajorShaderModel() const
{
return D3DSHADER_VERSION_MAJOR(mDeviceCaps.PixelShaderVersion);
@@ -2578,6 +2360,7 @@ gl::Error Renderer9::createRenderTarget(int width, int height, GLenum format, GL
const gl::TextureCaps &textureCaps = getRendererTextureCaps().get(format);
GLuint supportedSamples = textureCaps.getNearestSamples(samples);
+ IDirect3DTexture9 *texture = nullptr;
IDirect3DSurface9 *renderTarget = NULL;
if (width > 0 && height > 0)
{
@@ -2593,10 +2376,23 @@ gl::Error Renderer9::createRenderTarget(int width, int height, GLenum format, GL
}
else
{
- requiresInitialization = (d3d9FormatInfo.dataInitializerFunction != NULL);
- result = mDevice->CreateRenderTarget(width, height, d3d9FormatInfo.renderFormat,
- gl_d3d9::GetMultisampleType(supportedSamples),
- 0, FALSE, &renderTarget, NULL);
+ requiresInitialization = (d3d9FormatInfo.dataInitializerFunction != nullptr);
+ if (supportedSamples > 0)
+ {
+ result = mDevice->CreateRenderTarget(width, height, d3d9FormatInfo.renderFormat,
+ gl_d3d9::GetMultisampleType(supportedSamples),
+ 0, FALSE, &renderTarget, nullptr);
+ }
+ else
+ {
+ result = mDevice->CreateTexture(
+ width, height, 1, D3DUSAGE_RENDERTARGET, d3d9FormatInfo.texFormat,
+ getTexturePool(D3DUSAGE_RENDERTARGET), &texture, nullptr);
+ if (!FAILED(result))
+ {
+ result = texture->GetSurfaceLevel(0, &renderTarget);
+ }
+ }
}
if (FAILED(result))
@@ -2618,13 +2414,36 @@ gl::Error Renderer9::createRenderTarget(int width, int height, GLenum format, GL
}
}
- *outRT = new TextureRenderTarget9(renderTarget, format, width, height, 1, supportedSamples);
+ *outRT = new TextureRenderTarget9(texture, 0, renderTarget, format, width, height, 1,
+ supportedSamples);
return gl::Error(GL_NO_ERROR);
}
-FramebufferImpl *Renderer9::createDefaultFramebuffer(const gl::Framebuffer::Data &data)
+gl::Error Renderer9::createRenderTargetCopy(RenderTargetD3D *source, RenderTargetD3D **outRT)
{
- return createFramebuffer(data);
+ ASSERT(source != nullptr);
+
+ RenderTargetD3D *newRT = nullptr;
+ gl::Error error = createRenderTarget(source->getWidth(), source->getHeight(),
+ source->getInternalFormat(), source->getSamples(), &newRT);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ RenderTarget9 *source9 = GetAs<RenderTarget9>(source);
+ RenderTarget9 *dest9 = GetAs<RenderTarget9>(newRT);
+
+ HRESULT result = mDevice->StretchRect(source9->getSurface(), nullptr, dest9->getSurface(),
+ nullptr, D3DTEXF_NONE);
+ if (FAILED(result))
+ {
+ ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
+ return gl::Error(GL_OUT_OF_MEMORY, "Failed to copy render target, result: 0x%X.", result);
+ }
+
+ *outRT = newRT;
+ return gl::Error(GL_NO_ERROR);
}
FramebufferImpl *Renderer9::createFramebuffer(const gl::Framebuffer::Data &data)
@@ -2632,27 +2451,25 @@ FramebufferImpl *Renderer9::createFramebuffer(const gl::Framebuffer::Data &data)
return new Framebuffer9(data, this);
}
-CompilerImpl *Renderer9::createCompiler(const gl::Data &data)
+ShaderImpl *Renderer9::createShader(const gl::Shader::Data &data)
{
- return new CompilerD3D(data, SH_HLSL9_OUTPUT);
+ return new ShaderD3D(data);
}
-ShaderImpl *Renderer9::createShader(GLenum type)
+ProgramImpl *Renderer9::createProgram(const gl::Program::Data &data)
{
- return new ShaderD3D(type);
+ return new ProgramD3D(data, this);
}
-ProgramImpl *Renderer9::createProgram()
-{
- return new ProgramD3D(this);
-}
-
-gl::Error Renderer9::loadExecutable(const void *function, size_t length, ShaderType type,
- const std::vector<gl::LinkedVarying> &transformFeedbackVaryings,
- bool separatedOutputBuffers, ShaderExecutableD3D **outExecutable)
+gl::Error Renderer9::loadExecutable(const void *function,
+ size_t length,
+ ShaderType type,
+ const std::vector<D3DVarying> &streamOutVaryings,
+ bool separatedOutputBuffers,
+ ShaderExecutableD3D **outExecutable)
{
// Transform feedback is not supported in ES2 or D3D9
- ASSERT(transformFeedbackVaryings.size() == 0);
+ ASSERT(streamOutVaryings.empty());
switch (type)
{
@@ -2686,13 +2503,16 @@ gl::Error Renderer9::loadExecutable(const void *function, size_t length, ShaderT
return gl::Error(GL_NO_ERROR);
}
-gl::Error Renderer9::compileToExecutable(gl::InfoLog &infoLog, const std::string &shaderHLSL, ShaderType type,
- const std::vector<gl::LinkedVarying> &transformFeedbackVaryings,
- bool separatedOutputBuffers, const D3DCompilerWorkarounds &workarounds,
+gl::Error Renderer9::compileToExecutable(gl::InfoLog &infoLog,
+ const std::string &shaderHLSL,
+ ShaderType type,
+ const std::vector<D3DVarying> &streamOutVaryings,
+ bool separatedOutputBuffers,
+ const D3DCompilerWorkarounds &workarounds,
ShaderExecutableD3D **outExectuable)
{
// Transform feedback is not supported in ES2 or D3D9
- ASSERT(transformFeedbackVaryings.size() == 0);
+ ASSERT(streamOutVaryings.empty());
const char *profileType = NULL;
switch (type)
@@ -2755,7 +2575,7 @@ gl::Error Renderer9::compileToExecutable(gl::InfoLog &infoLog, const std::string
}
error = loadExecutable(binary->GetBufferPointer(), binary->GetBufferSize(), type,
- transformFeedbackVaryings, separatedOutputBuffers, outExectuable);
+ streamOutVaryings, separatedOutputBuffers, outExectuable);
SafeRelease(binary);
if (error.isError())
@@ -2841,17 +2661,29 @@ ImageD3D *Renderer9::createImage()
gl::Error Renderer9::generateMipmap(ImageD3D *dest, ImageD3D *src)
{
- Image9 *src9 = Image9::makeImage9(src);
- Image9 *dst9 = Image9::makeImage9(dest);
+ Image9 *src9 = GetAs<Image9>(src);
+ Image9 *dst9 = GetAs<Image9>(dest);
return Image9::generateMipmap(dst9, src9);
}
+gl::Error Renderer9::generateMipmapsUsingD3D(TextureStorage *storage,
+ const gl::TextureState &textureState)
+{
+ UNREACHABLE();
+ return gl::Error(GL_NO_ERROR);
+}
+
TextureStorage *Renderer9::createTextureStorage2D(SwapChainD3D *swapChain)
{
- SwapChain9 *swapChain9 = SwapChain9::makeSwapChain9(swapChain);
+ SwapChain9 *swapChain9 = GetAs<SwapChain9>(swapChain);
return new TextureStorage9_2D(this, swapChain9);
}
+TextureStorage *Renderer9::createTextureStorageEGLImage(EGLImageD3D *eglImage)
+{
+ return new TextureStorage9_EGLImage(this, eglImage);
+}
+
TextureStorage *Renderer9::createTextureStorage2D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels, bool hintLevelZeroOnly)
{
return new TextureStorage9_2D(this, internalformat, renderTarget, width, height, levels);
@@ -2910,24 +2742,75 @@ bool Renderer9::getLUID(LUID *adapterLuid) const
return false;
}
-VertexConversionType Renderer9::getVertexConversionType(const gl::VertexFormat &vertexFormat) const
+VertexConversionType Renderer9::getVertexConversionType(gl::VertexFormatType vertexFormatType) const
{
- return d3d9::GetVertexFormatInfo(getCapsDeclTypes(), vertexFormat).conversionType;
+ return d3d9::GetVertexFormatInfo(getCapsDeclTypes(), vertexFormatType).conversionType;
}
-GLenum Renderer9::getVertexComponentType(const gl::VertexFormat &vertexFormat) const
+GLenum Renderer9::getVertexComponentType(gl::VertexFormatType vertexFormatType) const
{
- return d3d9::GetVertexFormatInfo(getCapsDeclTypes(), vertexFormat).componentType;
+ return d3d9::GetVertexFormatInfo(getCapsDeclTypes(), vertexFormatType).componentType;
}
-void Renderer9::generateCaps(gl::Caps *outCaps, gl::TextureCapsMap *outTextureCaps, gl::Extensions *outExtensions) const
+void Renderer9::generateCaps(gl::Caps *outCaps,
+ gl::TextureCapsMap *outTextureCaps,
+ gl::Extensions *outExtensions,
+ gl::Limitations *outLimitations) const
{
- d3d9_gl::GenerateCaps(mD3d9, mDevice, mDeviceType, mAdapter, outCaps, outTextureCaps, outExtensions);
+ d3d9_gl::GenerateCaps(mD3d9, mDevice, mDeviceType, mAdapter, outCaps, outTextureCaps,
+ outExtensions, outLimitations);
}
-Workarounds Renderer9::generateWorkarounds() const
+WorkaroundsD3D Renderer9::generateWorkarounds() const
{
return d3d9::GenerateWorkarounds();
}
+void Renderer9::createAnnotator()
+{
+ mAnnotator = new DebugAnnotator9();
+}
+
+gl::Error Renderer9::clearTextures(gl::SamplerType samplerType, size_t rangeStart, size_t rangeEnd)
+{
+ // TODO(jmadill): faster way?
+ for (size_t samplerIndex = rangeStart; samplerIndex < rangeEnd; samplerIndex++)
+ {
+ gl::Error error = setTexture(samplerType, static_cast<int>(samplerIndex), nullptr);
+ if (error.isError())
+ {
+ return error;
+ }
+ }
+
+ return gl::Error(GL_NO_ERROR);
+}
+
+egl::Error Renderer9::getEGLDevice(DeviceImpl **device)
+{
+ if (mEGLDevice == nullptr)
+ {
+ ASSERT(mDevice != nullptr);
+ mEGLDevice = new DeviceD3D();
+ egl::Error error = mEGLDevice->initialize(reinterpret_cast<void *>(mDevice),
+ EGL_D3D9_DEVICE_ANGLE, EGL_FALSE);
+
+ if (error.isError())
+ {
+ SafeDelete(mEGLDevice);
+ return error;
+ }
+ }
+
+ *device = static_cast<DeviceImpl *>(mEGLDevice);
+ return egl::Error(EGL_SUCCESS);
+}
+
+Renderer9::CurSamplerState::CurSamplerState()
+ : forceSet(true),
+ baseLevel(std::numeric_limits<size_t>::max()),
+ samplerState()
+{
+}
+
}
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Renderer9.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Renderer9.h
index 19bea3eb35..a0dfecb02e 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Renderer9.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Renderer9.h
@@ -17,6 +17,7 @@
#include "libANGLE/renderer/d3d/d3d9/DebugAnnotator9.h"
#include "libANGLE/renderer/d3d/d3d9/ShaderCache.h"
#include "libANGLE/renderer/d3d/d3d9/VertexDeclarationCache.h"
+#include "libANGLE/renderer/d3d/d3d9/StateManager9.h"
namespace gl
{
@@ -32,10 +33,12 @@ namespace rx
{
class Blit9;
class IndexDataManager;
+class ProgramD3D;
class StreamingIndexBufferInterface;
class StaticIndexBufferInterface;
class VertexDataManager;
struct ClearParameters;
+struct D3DUniform;
struct TranslatedAttribute;
enum D3D9InitError
@@ -64,12 +67,11 @@ class Renderer9 : public RendererD3D
explicit Renderer9(egl::Display *display);
virtual ~Renderer9();
- static Renderer9 *makeRenderer9(Renderer *renderer);
-
egl::Error initialize() override;
virtual bool resetDevice();
egl::ConfigSet generateConfigs() const override;
+ void generateDisplayExtensions(egl::DisplayExtensions *outExtensions) const override;
void startScene();
void endScene();
@@ -77,7 +79,13 @@ class Renderer9 : public RendererD3D
gl::Error flush() override;
gl::Error finish() override;
- virtual SwapChainD3D *createSwapChain(NativeWindow nativeWindow, HANDLE shareHandle, GLenum backBufferFormat, GLenum depthBufferFormat);
+ SwapChainD3D *createSwapChain(NativeWindow nativeWindow,
+ HANDLE shareHandle,
+ GLenum backBufferFormat,
+ GLenum depthBufferFormat,
+ EGLint orientation) override;
+
+ CompilerImpl *createCompiler() override;
gl::Error allocateEventQuery(IDirect3DQuery9 **outQuery);
void freeEventQuery(IDirect3DQuery9* query);
@@ -92,34 +100,42 @@ class Renderer9 : public RendererD3D
virtual gl::Error setTexture(gl::SamplerType type, int index, gl::Texture *texture);
gl::Error setUniformBuffers(const gl::Data &data,
- const GLint vertexUniformBuffers[],
- const GLint fragmentUniformBuffers[]) override;
+ const std::vector<GLint> &vertexUniformBuffers,
+ const std::vector<GLint> &fragmentUniformBuffers) override;
- virtual gl::Error setRasterizerState(const gl::RasterizerState &rasterState);
- gl::Error setBlendState(const gl::Framebuffer *framebuffer, const gl::BlendState &blendState, const gl::ColorF &blendColor,
- unsigned int sampleMask) override;
- virtual gl::Error setDepthStencilState(const gl::DepthStencilState &depthStencilState, int stencilRef,
- int stencilBackRef, bool frontFaceCCW);
+ gl::Error updateState(const gl::Data &data, GLenum drawMode) override;
- virtual void setScissorRectangle(const gl::Rectangle &scissor, bool enabled);
- virtual void setViewport(const gl::Rectangle &viewport, float zNear, float zFar, GLenum drawMode, GLenum frontFace,
- bool ignoreViewport);
+ void setScissorRectangle(const gl::Rectangle &scissor, bool enabled);
+ void setViewport(const gl::Caps *caps,
+ const gl::Rectangle &viewport,
+ float zNear,
+ float zFar,
+ GLenum drawMode,
+ GLenum frontFace,
+ bool ignoreViewport);
gl::Error applyRenderTarget(const gl::Framebuffer *frameBuffer) override;
- gl::Error applyRenderTarget(const gl::FramebufferAttachment *colorBuffer, const gl::FramebufferAttachment *depthStencilBuffer);
- virtual gl::Error applyShaders(gl::Program *program, const gl::VertexFormat inputLayout[], const gl::Framebuffer *framebuffer,
- bool rasterizerDiscard, bool transformFeedbackActive);
- virtual gl::Error applyUniforms(const ProgramImpl &program, const std::vector<gl::LinkedUniform*> &uniformArray);
+ gl::Error applyRenderTarget(const gl::FramebufferAttachment *colorAttachment,
+ const gl::FramebufferAttachment *depthStencilAttachment);
+ gl::Error applyUniforms(const ProgramD3D &programD3D,
+ GLenum drawMode,
+ const std::vector<D3DUniform *> &uniformArray) override;
virtual bool applyPrimitiveType(GLenum primitiveType, GLsizei elementCount, bool usesPointSize);
- virtual gl::Error applyVertexBuffer(const gl::State &state, GLenum mode, GLint first, GLsizei count, GLsizei instances);
- virtual gl::Error applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo);
+ virtual gl::Error applyVertexBuffer(const gl::State &state,
+ GLenum mode,
+ GLint first,
+ GLsizei count,
+ GLsizei instances,
+ TranslatedIndexData *indexInfo);
+ gl::Error applyIndexBuffer(const gl::Data &data,
+ const GLvoid *indices,
+ GLsizei count,
+ GLenum mode,
+ GLenum type,
+ TranslatedIndexData *indexInfo) override;
void applyTransformFeedbackBuffers(const gl::State &state) override;
- gl::Error drawArrays(const gl::Data &data, GLenum mode, GLsizei count, GLsizei instances, bool usesPointSize) override;
- virtual gl::Error drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices,
- gl::Buffer *elementArrayBuffer, const TranslatedIndexData &indexInfo, GLsizei instances);
-
gl::Error clear(const ClearParameters &clearParams,
const gl::FramebufferAttachment *colorBuffer,
const gl::FramebufferAttachment *depthStencilBuffer);
@@ -130,18 +146,19 @@ class Renderer9 : public RendererD3D
bool testDeviceLost() override;
bool testDeviceResettable() override;
- VendorID getVendorId() const override;
+ VendorID getVendorId() const;
std::string getRendererDescription() const override;
- GUID getAdapterIdentifier() const override;
+ DeviceIdentifier getAdapterIdentifier() const override;
IDirect3DDevice9 *getDevice() { return mDevice; }
+ void *getD3DDevice() override;
virtual unsigned int getReservedVertexUniformVectors() const;
virtual unsigned int getReservedFragmentUniformVectors() const;
virtual unsigned int getReservedVertexUniformBuffers() const;
virtual unsigned int getReservedFragmentUniformBuffers() const;
- virtual bool getShareHandleSupport() const;
- virtual bool getPostSubBufferSupport() const;
+
+ bool getShareHandleSupport() const;
virtual int getMajorShaderModel() const;
int getMinorShaderModel() const override;
@@ -161,30 +178,38 @@ class Renderer9 : public RendererD3D
// RenderTarget creation
virtual gl::Error createRenderTarget(int width, int height, GLenum format, GLsizei samples, RenderTargetD3D **outRT);
+ gl::Error createRenderTargetCopy(RenderTargetD3D *source, RenderTargetD3D **outRT) override;
// Framebuffer creation
- FramebufferImpl *createDefaultFramebuffer(const gl::Framebuffer::Data &data) override;
FramebufferImpl *createFramebuffer(const gl::Framebuffer::Data &data) override;
// Shader creation
- virtual CompilerImpl *createCompiler(const gl::Data &data);
- virtual ShaderImpl *createShader(GLenum type);
- virtual ProgramImpl *createProgram();
+ ShaderImpl *createShader(const gl::Shader::Data &data) override;
+ ProgramImpl *createProgram(const gl::Program::Data &data) override;
// Shader operations
- virtual gl::Error loadExecutable(const void *function, size_t length, ShaderType type,
- const std::vector<gl::LinkedVarying> &transformFeedbackVaryings,
- bool separatedOutputBuffers, ShaderExecutableD3D **outExecutable);
- virtual gl::Error compileToExecutable(gl::InfoLog &infoLog, const std::string &shaderHLSL, ShaderType type,
- const std::vector<gl::LinkedVarying> &transformFeedbackVaryings,
- bool separatedOutputBuffers, const D3DCompilerWorkarounds &workarounds,
- ShaderExecutableD3D **outExectuable);
- virtual UniformStorageD3D *createUniformStorage(size_t storageSize);
+ gl::Error loadExecutable(const void *function,
+ size_t length,
+ ShaderType type,
+ const std::vector<D3DVarying> &streamOutVaryings,
+ bool separatedOutputBuffers,
+ ShaderExecutableD3D **outExecutable) override;
+ gl::Error compileToExecutable(gl::InfoLog &infoLog,
+ const std::string &shaderHLSL,
+ ShaderType type,
+ const std::vector<D3DVarying> &streamOutVaryings,
+ bool separatedOutputBuffers,
+ const D3DCompilerWorkarounds &workarounds,
+ ShaderExecutableD3D **outExectuable) override;
+ UniformStorageD3D *createUniformStorage(size_t storageSize) override;
// Image operations
virtual ImageD3D *createImage();
gl::Error generateMipmap(ImageD3D *dest, ImageD3D *source) override;
+ gl::Error generateMipmapsUsingD3D(TextureStorage *storage,
+ const gl::TextureState &textureState) override;
virtual TextureStorage *createTextureStorage2D(SwapChainD3D *swapChain);
+ TextureStorage *createTextureStorageEGLImage(EGLImageD3D *eglImage) override;
virtual TextureStorage *createTextureStorage2D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels, bool hintLevelZeroOnly);
virtual TextureStorage *createTextureStorageCube(GLenum internalformat, bool renderTarget, int size, int levels, bool hintLevelZeroOnly);
virtual TextureStorage *createTextureStorage3D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels);
@@ -202,7 +227,7 @@ class Renderer9 : public RendererD3D
virtual IndexBuffer *createIndexBuffer();
// Vertex Array creation
- virtual VertexArrayImpl *createVertexArray();
+ VertexArrayImpl *createVertexArray(const gl::VertexArray::Data &data) override;
// Query and Fence creation
virtual QueryImpl *createQuery(GLenum type);
@@ -217,14 +242,16 @@ class Renderer9 : public RendererD3D
virtual gl::Error fastCopyBufferToTexture(const gl::PixelUnpackState &unpack, unsigned int offset, RenderTargetD3D *destRenderTarget,
GLenum destinationFormat, GLenum sourcePixelsType, const gl::Box &destArea);
+ void syncState(const gl::State &state, const gl::State::DirtyBits &bitmask) override;
+
// D3D9-renderer specific methods
gl::Error boxFilter(IDirect3DSurface9 *source, IDirect3DSurface9 *dest);
D3DPOOL getTexturePool(DWORD usage) const;
bool getLUID(LUID *adapterLuid) const override;
- virtual VertexConversionType getVertexConversionType(const gl::VertexFormat &vertexFormat) const;
- virtual GLenum getVertexComponentType(const gl::VertexFormat &vertexFormat) const;
+ VertexConversionType getVertexConversionType(gl::VertexFormatType vertexFormatType) const override;
+ GLenum getVertexComponentType(gl::VertexFormatType vertexFormatType) const override;
gl::Error copyToRenderTarget(IDirect3DSurface9 *dest, IDirect3DSurface9 *source, bool fromManaged);
@@ -232,15 +259,39 @@ class Renderer9 : public RendererD3D
D3DDEVTYPE getD3D9DeviceType() const { return mDeviceType; }
+ egl::Error getEGLDevice(DeviceImpl **device) override;
+
+ protected:
+ void createAnnotator() override;
+ gl::Error clearTextures(gl::SamplerType samplerType, size_t rangeStart, size_t rangeEnd) override;
+ gl::Error applyShadersImpl(const gl::Data &data, GLenum drawMode) override;
+
private:
- void generateCaps(gl::Caps *outCaps, gl::TextureCapsMap *outTextureCaps, gl::Extensions *outExtensions) const override;
- Workarounds generateWorkarounds() const override;
+ gl::Error drawArraysImpl(const gl::Data &data,
+ GLenum mode,
+ GLsizei count,
+ GLsizei instances) override;
+ gl::Error drawElementsImpl(const gl::Data &data,
+ const TranslatedIndexData &indexInfo,
+ GLenum mode,
+ GLsizei count,
+ GLenum type,
+ const GLvoid *indices,
+ GLsizei instances) override;
+
+ void generateCaps(gl::Caps *outCaps, gl::TextureCapsMap *outTextureCaps,
+ gl::Extensions *outExtensions,
+ gl::Limitations *outLimitations) const override;
+
+ WorkaroundsD3D generateWorkarounds() const override;
+
+ gl::Error setBlendDepthRasterStates(const gl::Data &glData, GLenum drawMode);
void release();
- void applyUniformnfv(gl::LinkedUniform *targetUniform, const GLfloat *v);
- void applyUniformniv(gl::LinkedUniform *targetUniform, const GLint *v);
- void applyUniformnbv(gl::LinkedUniform *targetUniform, const GLint *v);
+ void applyUniformnfv(const D3DUniform *targetUniform, const GLfloat *v);
+ void applyUniformniv(const D3DUniform *targetUniform, const GLint *v);
+ void applyUniformnbv(const D3DUniform *targetUniform, const GLint *v);
gl::Error drawLineLoop(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer);
gl::Error drawIndexedPoints(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer);
@@ -290,64 +341,32 @@ class Renderer9 : public RendererD3D
unsigned int mAppliedDepthStencilSerial;
bool mDepthStencilInitialized;
bool mRenderTargetDescInitialized;
- unsigned int mCurStencilSize;
- unsigned int mCurDepthSize;
-
- struct RenderTargetDesc
- {
- size_t width;
- size_t height;
- D3DFORMAT format;
- };
- RenderTargetDesc mRenderTargetDesc;
IDirect3DStateBlock9 *mMaskedClearSavedState;
- // previously set render states
- bool mForceSetDepthStencilState;
- gl::DepthStencilState mCurDepthStencilState;
- int mCurStencilRef;
- int mCurStencilBackRef;
- bool mCurFrontFaceCCW;
-
- bool mForceSetRasterState;
- gl::RasterizerState mCurRasterState;
-
- bool mForceSetScissor;
- gl::Rectangle mCurScissor;
- bool mScissorEnabled;
-
- bool mForceSetViewport;
- gl::Rectangle mCurViewport;
- float mCurNear;
- float mCurFar;
- float mCurDepthFront;
-
- bool mForceSetBlendState;
- gl::BlendState mCurBlendState;
- gl::ColorF mCurBlendColor;
- GLuint mCurSampleMask;
+ StateManager9 mStateManager;
// Currently applied sampler states
- std::vector<bool> mForceSetVertexSamplerStates;
- std::vector<gl::SamplerState> mCurVertexSamplerStates;
+ struct CurSamplerState
+ {
+ CurSamplerState();
- std::vector<bool> mForceSetPixelSamplerStates;
- std::vector<gl::SamplerState> mCurPixelSamplerStates;
+ bool forceSet;
+ size_t baseLevel;
+ gl::SamplerState samplerState;
+ };
+ std::vector<CurSamplerState> mCurVertexSamplerStates;
+ std::vector<CurSamplerState> mCurPixelSamplerStates;
// Currently applied textures
- std::vector<unsigned int> mCurVertexTextureSerials;
- std::vector<unsigned int> mCurPixelTextureSerials;
+ std::vector<uintptr_t> mCurVertexTextures;
+ std::vector<uintptr_t> mCurPixelTextures;
unsigned int mAppliedIBSerial;
IDirect3DVertexShader9 *mAppliedVertexShader;
IDirect3DPixelShader9 *mAppliedPixelShader;
unsigned int mAppliedProgramSerial;
- dx_VertexConstants mVertexConstants;
- dx_PixelConstants mPixelConstants;
- bool mDxUniformsDirty;
-
// A pool of event queries that are currently unused.
std::vector<IDirect3DQuery9*> mEventQueryPool;
VertexShaderCache mVertexShaderCache;
@@ -370,7 +389,7 @@ class Renderer9 : public RendererD3D
} mNullColorbufferCache[NUM_NULL_COLORBUFFER_CACHE_ENTRIES];
UINT mMaxNullColorbufferLRU;
- DebugAnnotator9 mAnnotator;
+ DeviceD3D *mEGLDevice;
};
}
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/ShaderExecutable9.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/ShaderExecutable9.cpp
index 280e80930b..28a486056b 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/ShaderExecutable9.cpp
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/ShaderExecutable9.cpp
@@ -34,12 +34,6 @@ ShaderExecutable9::~ShaderExecutable9()
SafeRelease(mPixelExecutable);
}
-ShaderExecutable9 *ShaderExecutable9::makeShaderExecutable9(ShaderExecutableD3D *executable)
-{
- ASSERT(HAS_DYNAMIC_TYPE(ShaderExecutable9*, executable));
- return static_cast<ShaderExecutable9*>(executable);
-}
-
IDirect3DVertexShader9 *ShaderExecutable9::getVertexShader() const
{
return mVertexExecutable;
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/ShaderExecutable9.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/ShaderExecutable9.h
index 561f7defc8..382a68c820 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/ShaderExecutable9.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/ShaderExecutable9.h
@@ -22,8 +22,6 @@ class ShaderExecutable9 : public ShaderExecutableD3D
ShaderExecutable9(const void *function, size_t length, IDirect3DVertexShader9 *executable);
virtual ~ShaderExecutable9();
- static ShaderExecutable9 *makeShaderExecutable9(ShaderExecutableD3D *executable);
-
IDirect3DPixelShader9 *getPixelShader() const;
IDirect3DVertexShader9 *getVertexShader() const;
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/StateManager9.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/StateManager9.cpp
new file mode 100644
index 0000000000..c4c600aedb
--- /dev/null
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/StateManager9.cpp
@@ -0,0 +1,903 @@
+//
+// 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.
+//
+
+// StateManager9.cpp: Defines a class for caching D3D9 state
+#include "libANGLE/renderer/d3d/d3d9/StateManager9.h"
+
+#include "common/BitSetIterator.h"
+#include "common/utilities.h"
+#include "libANGLE/formatutils.h"
+#include "libANGLE/renderer/d3d/d3d9/renderer9_utils.h"
+#include "libANGLE/renderer/d3d/d3d9/Framebuffer9.h"
+#include "libANGLE/renderer/d3d/d3d9/Renderer9.h"
+
+namespace rx
+{
+
+StateManager9::StateManager9(Renderer9 *renderer9)
+ : mCurBlendState(),
+ mCurBlendColor(0, 0, 0, 0),
+ mCurSampleMask(0),
+ mCurRasterState(),
+ mCurDepthSize(0),
+ mCurDepthStencilState(),
+ mCurStencilRef(0),
+ mCurStencilBackRef(0),
+ mCurFrontFaceCCW(0),
+ mCurStencilSize(0),
+ mCurScissorRect(),
+ mCurScissorEnabled(false),
+ mCurViewport(),
+ mCurNear(0.0f),
+ mCurFar(0.0f),
+ mCurDepthFront(0.0f),
+ mCurIgnoreViewport(false),
+ mRenderer9(renderer9),
+ mDirtyBits()
+{
+ mBlendStateDirtyBits.set(DIRTY_BIT_BLEND_ENABLED);
+ mBlendStateDirtyBits.set(DIRTY_BIT_BLEND_COLOR);
+ mBlendStateDirtyBits.set(DIRTY_BIT_BLEND_FUNCS_EQUATIONS);
+ mBlendStateDirtyBits.set(DIRTY_BIT_SAMPLE_ALPHA_TO_COVERAGE);
+ mBlendStateDirtyBits.set(DIRTY_BIT_COLOR_MASK);
+ mBlendStateDirtyBits.set(DIRTY_BIT_DITHER);
+ mBlendStateDirtyBits.set(DIRTY_BIT_SAMPLE_MASK);
+
+ mRasterizerStateDirtyBits.set(DIRTY_BIT_CULL_MODE);
+ mRasterizerStateDirtyBits.set(DIRTY_BIT_DEPTH_BIAS);
+
+ mDepthStencilStateDirtyBits.set(DIRTY_BIT_STENCIL_DEPTH_MASK);
+ mDepthStencilStateDirtyBits.set(DIRTY_BIT_STENCIL_DEPTH_FUNC);
+ mDepthStencilStateDirtyBits.set(DIRTY_BIT_STENCIL_TEST_ENABLED);
+ mDepthStencilStateDirtyBits.set(DIRTY_BIT_STENCIL_FUNCS_FRONT);
+ mDepthStencilStateDirtyBits.set(DIRTY_BIT_STENCIL_FUNCS_BACK);
+ mDepthStencilStateDirtyBits.set(DIRTY_BIT_STENCIL_WRITEMASK_FRONT);
+ mDepthStencilStateDirtyBits.set(DIRTY_BIT_STENCIL_WRITEMASK_BACK);
+ mDepthStencilStateDirtyBits.set(DIRTY_BIT_STENCIL_OPS_FRONT);
+ mDepthStencilStateDirtyBits.set(DIRTY_BIT_STENCIL_OPS_BACK);
+
+ mScissorStateDirtyBits.set(DIRTY_BIT_SCISSOR_ENABLED);
+ mScissorStateDirtyBits.set(DIRTY_BIT_SCISSOR_RECT);
+}
+
+StateManager9::~StateManager9()
+{
+}
+
+void StateManager9::forceSetBlendState()
+{
+ mDirtyBits |= mBlendStateDirtyBits;
+}
+
+void StateManager9::forceSetRasterState()
+{
+ mDirtyBits |= mRasterizerStateDirtyBits;
+}
+
+void StateManager9::forceSetDepthStencilState()
+{
+ mDirtyBits |= mDepthStencilStateDirtyBits;
+}
+
+void StateManager9::forceSetScissorState()
+{
+ mDirtyBits |= mScissorStateDirtyBits;
+}
+
+void StateManager9::forceSetViewportState()
+{
+ mForceSetViewport = true;
+}
+
+void StateManager9::forceSetDXUniformsState()
+{
+ mDxUniformsDirty = true;
+}
+
+void StateManager9::updateStencilSizeIfChanged(bool depthStencilInitialized,
+ unsigned int stencilSize)
+{
+ if (!depthStencilInitialized || stencilSize != mCurStencilSize)
+ {
+ mCurStencilSize = stencilSize;
+ forceSetDepthStencilState();
+ }
+}
+
+void StateManager9::syncState(const gl::State &state, const gl::State::DirtyBits &dirtyBits)
+{
+ if (!dirtyBits.any())
+ {
+ return;
+ }
+
+ for (auto dirtyBit : angle::IterateBitSet(dirtyBits))
+ {
+ switch (dirtyBit)
+ {
+ case gl::State::DIRTY_BIT_BLEND_ENABLED:
+ if (state.getBlendState().blend != mCurBlendState.blend)
+ {
+ mDirtyBits.set(DIRTY_BIT_BLEND_ENABLED);
+ // BlendColor and funcs and equations has to be set if blend is enabled
+ mDirtyBits.set(DIRTY_BIT_BLEND_COLOR);
+ mDirtyBits.set(DIRTY_BIT_BLEND_FUNCS_EQUATIONS);
+ }
+ break;
+ case gl::State::DIRTY_BIT_BLEND_FUNCS:
+ {
+ const gl::BlendState &blendState = state.getBlendState();
+ if (blendState.sourceBlendRGB != mCurBlendState.sourceBlendRGB ||
+ blendState.destBlendRGB != mCurBlendState.destBlendRGB ||
+ blendState.sourceBlendAlpha != mCurBlendState.sourceBlendAlpha ||
+ blendState.destBlendAlpha != mCurBlendState.destBlendAlpha)
+ {
+ mDirtyBits.set(DIRTY_BIT_BLEND_FUNCS_EQUATIONS);
+ // BlendColor depends on the values of blend funcs
+ mDirtyBits.set(DIRTY_BIT_BLEND_COLOR);
+ }
+ break;
+ }
+ case gl::State::DIRTY_BIT_BLEND_EQUATIONS:
+ {
+ const gl::BlendState &blendState = state.getBlendState();
+ if (blendState.blendEquationRGB != mCurBlendState.blendEquationRGB ||
+ blendState.blendEquationAlpha != mCurBlendState.blendEquationAlpha)
+ {
+ mDirtyBits.set(DIRTY_BIT_BLEND_FUNCS_EQUATIONS);
+ }
+ break;
+ }
+ case gl::State::DIRTY_BIT_SAMPLE_ALPHA_TO_COVERAGE_ENABLED:
+ if (state.getBlendState().sampleAlphaToCoverage !=
+ mCurBlendState.sampleAlphaToCoverage)
+ {
+ mDirtyBits.set(DIRTY_BIT_SAMPLE_ALPHA_TO_COVERAGE);
+ }
+ break;
+ case gl::State::DIRTY_BIT_COLOR_MASK:
+ {
+ const gl::BlendState &blendState = state.getBlendState();
+ if (blendState.colorMaskRed != mCurBlendState.colorMaskRed ||
+ blendState.colorMaskGreen != mCurBlendState.colorMaskGreen ||
+ blendState.colorMaskBlue != mCurBlendState.colorMaskBlue ||
+ blendState.colorMaskAlpha != mCurBlendState.colorMaskAlpha)
+ {
+ mDirtyBits.set(DIRTY_BIT_COLOR_MASK);
+ }
+ break;
+ }
+ case gl::State::DIRTY_BIT_DITHER_ENABLED:
+ if (state.getBlendState().dither != mCurBlendState.dither)
+ {
+ mDirtyBits.set(DIRTY_BIT_DITHER);
+ }
+ break;
+ case gl::State::DIRTY_BIT_BLEND_COLOR:
+ if (state.getBlendColor() != mCurBlendColor)
+ {
+ mDirtyBits.set(DIRTY_BIT_BLEND_COLOR);
+ }
+ break;
+ case gl::State::DIRTY_BIT_CULL_FACE_ENABLED:
+ if (state.getRasterizerState().cullFace != mCurRasterState.cullFace)
+ {
+ mDirtyBits.set(DIRTY_BIT_CULL_MODE);
+ }
+ break;
+ case gl::State::DIRTY_BIT_CULL_FACE:
+ if (state.getRasterizerState().cullMode != mCurRasterState.cullMode)
+ {
+ mDirtyBits.set(DIRTY_BIT_CULL_MODE);
+ }
+ break;
+ case gl::State::DIRTY_BIT_FRONT_FACE:
+ if (state.getRasterizerState().frontFace != mCurRasterState.frontFace)
+ {
+ mDirtyBits.set(DIRTY_BIT_CULL_MODE);
+
+ // Viewport state depends on rasterizer.frontface
+ mDirtyBits.set(DIRTY_BIT_VIEWPORT);
+ }
+ break;
+ case gl::State::DIRTY_BIT_POLYGON_OFFSET_FILL_ENABLED:
+ if (state.getRasterizerState().polygonOffsetFill !=
+ mCurRasterState.polygonOffsetFill)
+ {
+ mDirtyBits.set(DIRTY_BIT_DEPTH_BIAS);
+ }
+ break;
+ case gl::State::DIRTY_BIT_POLYGON_OFFSET:
+ {
+ const gl::RasterizerState &rasterizerState = state.getRasterizerState();
+ if (rasterizerState.polygonOffsetFactor != mCurRasterState.polygonOffsetFactor ||
+ rasterizerState.polygonOffsetUnits != mCurRasterState.polygonOffsetUnits)
+ {
+ mDirtyBits.set(DIRTY_BIT_DEPTH_BIAS);
+ }
+ }
+ case gl::State::DIRTY_BIT_DEPTH_MASK:
+ if (state.getDepthStencilState().depthMask != mCurDepthStencilState.depthMask)
+ {
+ mDirtyBits.set(DIRTY_BIT_STENCIL_DEPTH_MASK);
+ }
+ break;
+ case gl::State::DIRTY_BIT_DEPTH_TEST_ENABLED:
+ if (state.getDepthStencilState().depthTest != mCurDepthStencilState.depthTest)
+ {
+ mDirtyBits.set(DIRTY_BIT_STENCIL_DEPTH_FUNC);
+ }
+ break;
+ case gl::State::DIRTY_BIT_DEPTH_FUNC:
+ if (state.getDepthStencilState().depthFunc != mCurDepthStencilState.depthFunc)
+ {
+ mDirtyBits.set(DIRTY_BIT_STENCIL_DEPTH_FUNC);
+ }
+ break;
+ case gl::State::DIRTY_BIT_STENCIL_TEST_ENABLED:
+ if (state.getDepthStencilState().stencilTest != mCurDepthStencilState.stencilTest)
+ {
+ mDirtyBits.set(DIRTY_BIT_STENCIL_TEST_ENABLED);
+ // If we enable the stencil test, all of these must be set
+ mDirtyBits.set(DIRTY_BIT_STENCIL_WRITEMASK_BACK);
+ mDirtyBits.set(DIRTY_BIT_STENCIL_WRITEMASK_FRONT);
+ mDirtyBits.set(DIRTY_BIT_STENCIL_FUNCS_FRONT);
+ mDirtyBits.set(DIRTY_BIT_STENCIL_FUNCS_BACK);
+ mDirtyBits.set(DIRTY_BIT_STENCIL_OPS_FRONT);
+ mDirtyBits.set(DIRTY_BIT_STENCIL_OPS_BACK);
+ }
+ break;
+ case gl::State::DIRTY_BIT_STENCIL_FUNCS_FRONT:
+ {
+ const gl::DepthStencilState &depthStencilState = state.getDepthStencilState();
+ if (depthStencilState.stencilFunc != mCurDepthStencilState.stencilFunc ||
+ depthStencilState.stencilMask != mCurDepthStencilState.stencilMask ||
+ state.getStencilRef() != mCurStencilRef)
+ {
+ mDirtyBits.set(DIRTY_BIT_STENCIL_FUNCS_FRONT);
+ }
+ break;
+ }
+ case gl::State::DIRTY_BIT_STENCIL_FUNCS_BACK:
+ {
+ const gl::DepthStencilState &depthStencilState = state.getDepthStencilState();
+ if (depthStencilState.stencilBackFunc != mCurDepthStencilState.stencilBackFunc ||
+ depthStencilState.stencilBackMask != mCurDepthStencilState.stencilBackMask ||
+ state.getStencilBackRef() != mCurStencilBackRef)
+ {
+ mDirtyBits.set(DIRTY_BIT_STENCIL_FUNCS_BACK);
+ }
+ break;
+ }
+ case gl::State::DIRTY_BIT_STENCIL_WRITEMASK_FRONT:
+ if (state.getDepthStencilState().stencilWritemask !=
+ mCurDepthStencilState.stencilWritemask)
+ {
+ mDirtyBits.set(DIRTY_BIT_STENCIL_WRITEMASK_FRONT);
+ }
+ break;
+ case gl::State::DIRTY_BIT_STENCIL_WRITEMASK_BACK:
+ if (state.getDepthStencilState().stencilBackWritemask !=
+ mCurDepthStencilState.stencilBackWritemask)
+ {
+ mDirtyBits.set(DIRTY_BIT_STENCIL_WRITEMASK_BACK);
+ }
+ break;
+ case gl::State::DIRTY_BIT_STENCIL_OPS_FRONT:
+ {
+ const gl::DepthStencilState &depthStencilState = state.getDepthStencilState();
+ if (depthStencilState.stencilFail != mCurDepthStencilState.stencilFail ||
+ depthStencilState.stencilPassDepthFail !=
+ mCurDepthStencilState.stencilPassDepthFail ||
+ depthStencilState.stencilPassDepthPass !=
+ mCurDepthStencilState.stencilPassDepthPass)
+ {
+ mDirtyBits.set(DIRTY_BIT_STENCIL_OPS_FRONT);
+ }
+ break;
+ }
+ case gl::State::DIRTY_BIT_STENCIL_OPS_BACK:
+ {
+ const gl::DepthStencilState &depthStencilState = state.getDepthStencilState();
+ if (depthStencilState.stencilBackFail != mCurDepthStencilState.stencilBackFail ||
+ depthStencilState.stencilBackPassDepthFail !=
+ mCurDepthStencilState.stencilBackPassDepthFail ||
+ depthStencilState.stencilBackPassDepthPass !=
+ mCurDepthStencilState.stencilBackPassDepthPass)
+ {
+ mDirtyBits.set(DIRTY_BIT_STENCIL_OPS_BACK);
+ }
+ break;
+ }
+ case gl::State::DIRTY_BIT_SCISSOR_TEST_ENABLED:
+ if (state.isScissorTestEnabled() != mCurScissorEnabled)
+ {
+ mDirtyBits.set(DIRTY_BIT_SCISSOR_ENABLED);
+ // If scissor is enabled, we have to set the scissor rect
+ mDirtyBits.set(DIRTY_BIT_SCISSOR_RECT);
+ }
+ break;
+ case gl::State::DIRTY_BIT_SCISSOR:
+ if (state.getScissor() != mCurScissorRect)
+ {
+ mDirtyBits.set(DIRTY_BIT_SCISSOR_RECT);
+ }
+ break;
+ case gl::State::DIRTY_BIT_DEPTH_RANGE:
+ if (state.getNearPlane() != mCurNear || state.getFarPlane() != mCurFar)
+ {
+ mDirtyBits.set(DIRTY_BIT_VIEWPORT);
+ }
+ break;
+ case gl::State::DIRTY_BIT_VIEWPORT:
+ if (state.getViewport() != mCurViewport)
+ {
+ mDirtyBits.set(DIRTY_BIT_VIEWPORT);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+gl::Error StateManager9::setBlendDepthRasterStates(const gl::State &glState,
+ unsigned int sampleMask)
+{
+ const gl::Framebuffer *framebuffer = glState.getDrawFramebuffer();
+
+ const gl::BlendState &blendState = glState.getBlendState();
+ const gl::ColorF &blendColor = glState.getBlendColor();
+ const gl::RasterizerState &rasterState = glState.getRasterizerState();
+
+ const auto &depthStencilState = glState.getDepthStencilState();
+ bool frontFaceCCW = (glState.getRasterizerState().frontFace == GL_CCW);
+ unsigned int maxStencil = (1 << mCurStencilSize) - 1;
+
+ // All the depth stencil states depends on the front face ccw variable
+ if (frontFaceCCW != mCurFrontFaceCCW)
+ {
+ forceSetDepthStencilState();
+ mCurFrontFaceCCW = frontFaceCCW;
+ }
+
+ for (auto dirtyBit : angle::IterateBitSet(mDirtyBits))
+ {
+ switch (dirtyBit)
+ {
+ case DIRTY_BIT_BLEND_ENABLED:
+ setBlendEnabled(blendState.blend);
+ break;
+ case DIRTY_BIT_BLEND_COLOR:
+ setBlendColor(blendState, blendColor);
+ break;
+ case DIRTY_BIT_BLEND_FUNCS_EQUATIONS:
+ setBlendFuncsEquations(blendState);
+ break;
+ case DIRTY_BIT_SAMPLE_ALPHA_TO_COVERAGE:
+ setSampleAlphaToCoverage(blendState.sampleAlphaToCoverage);
+ break;
+ case DIRTY_BIT_COLOR_MASK:
+ setColorMask(framebuffer, blendState.colorMaskRed, blendState.colorMaskBlue,
+ blendState.colorMaskGreen, blendState.colorMaskAlpha);
+ break;
+ case DIRTY_BIT_DITHER:
+ setDither(blendState.dither);
+ break;
+ case DIRTY_BIT_CULL_MODE:
+ setCullMode(rasterState.cullFace, rasterState.cullMode, rasterState.frontFace);
+ break;
+ case DIRTY_BIT_DEPTH_BIAS:
+ setDepthBias(rasterState.polygonOffsetFill, rasterState.polygonOffsetFactor,
+ rasterState.polygonOffsetUnits);
+ break;
+ case DIRTY_BIT_STENCIL_DEPTH_MASK:
+ setDepthMask(depthStencilState.depthMask);
+ break;
+ case DIRTY_BIT_STENCIL_DEPTH_FUNC:
+ setDepthFunc(depthStencilState.depthTest, depthStencilState.depthFunc);
+ break;
+ case DIRTY_BIT_STENCIL_TEST_ENABLED:
+ setStencilTestEnabled(depthStencilState.stencilTest);
+ break;
+ case DIRTY_BIT_STENCIL_FUNCS_FRONT:
+ setStencilFuncsFront(depthStencilState.stencilFunc, depthStencilState.stencilMask,
+ glState.getStencilRef(), frontFaceCCW, maxStencil);
+ break;
+ case DIRTY_BIT_STENCIL_FUNCS_BACK:
+ setStencilFuncsBack(depthStencilState.stencilBackFunc,
+ depthStencilState.stencilBackMask, glState.getStencilBackRef(),
+ frontFaceCCW, maxStencil);
+ break;
+ case DIRTY_BIT_STENCIL_WRITEMASK_FRONT:
+ setStencilWriteMask(depthStencilState.stencilWritemask, frontFaceCCW);
+ break;
+ case DIRTY_BIT_STENCIL_WRITEMASK_BACK:
+ setStencilBackWriteMask(depthStencilState.stencilBackWritemask, frontFaceCCW);
+ break;
+ case DIRTY_BIT_STENCIL_OPS_FRONT:
+ setStencilOpsFront(depthStencilState.stencilFail,
+ depthStencilState.stencilPassDepthFail,
+ depthStencilState.stencilPassDepthPass, frontFaceCCW);
+ break;
+ case DIRTY_BIT_STENCIL_OPS_BACK:
+ setStencilOpsBack(depthStencilState.stencilBackFail,
+ depthStencilState.stencilBackPassDepthFail,
+ depthStencilState.stencilBackPassDepthPass, frontFaceCCW);
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (sampleMask != mCurSampleMask)
+ {
+ setSampleMask(sampleMask);
+ }
+
+ return gl::Error(GL_NO_ERROR);
+}
+
+void StateManager9::setViewportState(const gl::Caps *caps,
+ const gl::Rectangle &viewport,
+ float zNear,
+ float zFar,
+ GLenum drawMode,
+ GLenum frontFace,
+ bool ignoreViewport)
+{
+ if (!mDirtyBits.test(DIRTY_BIT_VIEWPORT) && mCurIgnoreViewport == ignoreViewport)
+ return;
+
+ gl::Rectangle actualViewport = viewport;
+ float actualZNear = gl::clamp01(zNear);
+ float actualZFar = gl::clamp01(zFar);
+
+ if (ignoreViewport)
+ {
+ actualViewport.x = 0;
+ actualViewport.y = 0;
+ actualViewport.width = static_cast<int>(mRenderTargetBounds.width);
+ actualViewport.height = static_cast<int>(mRenderTargetBounds.height);
+ actualZNear = 0.0f;
+ actualZFar = 1.0f;
+ }
+
+ D3DVIEWPORT9 dxViewport;
+ dxViewport.X = gl::clamp(actualViewport.x, 0, static_cast<int>(mRenderTargetBounds.width));
+ dxViewport.Y = gl::clamp(actualViewport.y, 0, static_cast<int>(mRenderTargetBounds.height));
+ dxViewport.Width =
+ gl::clamp(actualViewport.width, 0,
+ static_cast<int>(mRenderTargetBounds.width) - static_cast<int>(dxViewport.X));
+ dxViewport.Height =
+ gl::clamp(actualViewport.height, 0,
+ static_cast<int>(mRenderTargetBounds.height) - static_cast<int>(dxViewport.Y));
+ dxViewport.MinZ = actualZNear;
+ dxViewport.MaxZ = actualZFar;
+
+ float depthFront = !gl::IsTriangleMode(drawMode) ? 0.0f : (frontFace == GL_CCW ? 1.0f : -1.0f);
+
+ mRenderer9->getDevice()->SetViewport(&dxViewport);
+
+ mCurViewport = actualViewport;
+ mCurNear = actualZNear;
+ mCurFar = actualZFar;
+ mCurDepthFront = depthFront;
+ mCurIgnoreViewport = ignoreViewport;
+
+ // Setting shader constants
+ dx_VertexConstants9 vc = {};
+ dx_PixelConstants9 pc = {};
+
+ vc.viewAdjust[0] =
+ static_cast<float>((actualViewport.width - static_cast<int>(dxViewport.Width)) +
+ 2 * (actualViewport.x - static_cast<int>(dxViewport.X)) - 1) /
+ dxViewport.Width;
+ vc.viewAdjust[1] =
+ static_cast<float>((actualViewport.height - static_cast<int>(dxViewport.Height)) +
+ 2 * (actualViewport.y - static_cast<int>(dxViewport.Y)) - 1) /
+ dxViewport.Height;
+ vc.viewAdjust[2] = static_cast<float>(actualViewport.width) / dxViewport.Width;
+ vc.viewAdjust[3] = static_cast<float>(actualViewport.height) / dxViewport.Height;
+
+ pc.viewCoords[0] = actualViewport.width * 0.5f;
+ pc.viewCoords[1] = actualViewport.height * 0.5f;
+ pc.viewCoords[2] = actualViewport.x + (actualViewport.width * 0.5f);
+ pc.viewCoords[3] = actualViewport.y + (actualViewport.height * 0.5f);
+
+ pc.depthFront[0] = (actualZFar - actualZNear) * 0.5f;
+ pc.depthFront[1] = (actualZNear + actualZFar) * 0.5f;
+ pc.depthFront[2] = depthFront;
+
+ vc.depthRange[0] = actualZNear;
+ vc.depthRange[1] = actualZFar;
+ vc.depthRange[2] = actualZFar - actualZNear;
+
+ pc.depthRange[0] = actualZNear;
+ pc.depthRange[1] = actualZFar;
+ pc.depthRange[2] = actualZFar - actualZNear;
+
+ if (memcmp(&vc, &mVertexConstants, sizeof(dx_VertexConstants9)) != 0)
+ {
+ mVertexConstants = vc;
+ mDxUniformsDirty = true;
+ }
+
+ if (memcmp(&pc, &mPixelConstants, sizeof(dx_PixelConstants9)) != 0)
+ {
+ mPixelConstants = pc;
+ mDxUniformsDirty = true;
+ }
+
+ mForceSetViewport = false;
+}
+
+void StateManager9::setShaderConstants()
+{
+ if (!mDxUniformsDirty)
+ return;
+
+ IDirect3DDevice9 *device = mRenderer9->getDevice();
+ device->SetVertexShaderConstantF(0, reinterpret_cast<float *>(&mVertexConstants),
+ sizeof(dx_VertexConstants9) / sizeof(float[4]));
+ device->SetPixelShaderConstantF(0, reinterpret_cast<float *>(&mPixelConstants),
+ sizeof(dx_PixelConstants9) / sizeof(float[4]));
+ mDxUniformsDirty = false;
+}
+
+// This is separate from the main state loop because other functions
+// outside call only setScissorState to update scissor state
+void StateManager9::setScissorState(const gl::Rectangle &scissor, bool enabled)
+{
+ if (mDirtyBits.test(DIRTY_BIT_SCISSOR_ENABLED))
+ setScissorEnabled(enabled);
+
+ if (mDirtyBits.test(DIRTY_BIT_SCISSOR_RECT))
+ setScissorRect(scissor, enabled);
+}
+
+void StateManager9::setRenderTargetBounds(size_t width, size_t height)
+{
+ mRenderTargetBounds.width = (int)width;
+ mRenderTargetBounds.height = (int)height;
+ forceSetViewportState();
+}
+
+void StateManager9::setScissorEnabled(bool scissorEnabled)
+{
+ mRenderer9->getDevice()->SetRenderState(D3DRS_SCISSORTESTENABLE, scissorEnabled ? TRUE : FALSE);
+ mCurScissorEnabled = scissorEnabled;
+}
+
+void StateManager9::setScissorRect(const gl::Rectangle &scissor, bool enabled)
+{
+ if (!enabled)
+ return;
+
+ RECT rect;
+ rect.left = gl::clamp(scissor.x, 0, static_cast<int>(mRenderTargetBounds.width));
+ rect.top = gl::clamp(scissor.y, 0, static_cast<int>(mRenderTargetBounds.height));
+ rect.right =
+ gl::clamp(scissor.x + scissor.width, 0, static_cast<int>(mRenderTargetBounds.width));
+ rect.bottom =
+ gl::clamp(scissor.y + scissor.height, 0, static_cast<int>(mRenderTargetBounds.height));
+ mRenderer9->getDevice()->SetScissorRect(&rect);
+}
+
+void StateManager9::setDepthFunc(bool depthTest, GLenum depthFunc)
+{
+ if (depthTest)
+ {
+ IDirect3DDevice9 *device = mRenderer9->getDevice();
+ device->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE);
+ device->SetRenderState(D3DRS_ZFUNC, gl_d3d9::ConvertComparison(depthFunc));
+ }
+ else
+ {
+ mRenderer9->getDevice()->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE);
+ }
+
+ mCurDepthStencilState.depthTest = depthTest;
+ mCurDepthStencilState.depthFunc = depthFunc;
+}
+
+void StateManager9::setStencilOpsFront(GLenum stencilFail,
+ GLenum stencilPassDepthFail,
+ GLenum stencilPassDepthPass,
+ bool frontFaceCCW)
+{
+ // TODO(dianx) It may be slightly more efficient todo these and other similar areas
+ // with separate dirty bits.
+ IDirect3DDevice9 *device = mRenderer9->getDevice();
+ device->SetRenderState(frontFaceCCW ? D3DRS_STENCILFAIL : D3DRS_CCW_STENCILFAIL,
+ gl_d3d9::ConvertStencilOp(stencilFail));
+ device->SetRenderState(frontFaceCCW ? D3DRS_STENCILZFAIL : D3DRS_CCW_STENCILZFAIL,
+ gl_d3d9::ConvertStencilOp(stencilPassDepthFail));
+ device->SetRenderState(frontFaceCCW ? D3DRS_STENCILPASS : D3DRS_CCW_STENCILPASS,
+ gl_d3d9::ConvertStencilOp(stencilPassDepthPass));
+
+ mCurDepthStencilState.stencilFail = stencilFail;
+ mCurDepthStencilState.stencilPassDepthFail = stencilPassDepthFail;
+ mCurDepthStencilState.stencilPassDepthPass = stencilPassDepthPass;
+}
+
+void StateManager9::setStencilOpsBack(GLenum stencilBackFail,
+ GLenum stencilBackPassDepthFail,
+ GLenum stencilBackPassDepthPass,
+ bool frontFaceCCW)
+{
+ IDirect3DDevice9 *device = mRenderer9->getDevice();
+ device->SetRenderState(!frontFaceCCW ? D3DRS_STENCILFAIL : D3DRS_CCW_STENCILFAIL,
+ gl_d3d9::ConvertStencilOp(stencilBackFail));
+ device->SetRenderState(!frontFaceCCW ? D3DRS_STENCILZFAIL : D3DRS_CCW_STENCILZFAIL,
+ gl_d3d9::ConvertStencilOp(stencilBackPassDepthFail));
+ device->SetRenderState(!frontFaceCCW ? D3DRS_STENCILPASS : D3DRS_CCW_STENCILPASS,
+ gl_d3d9::ConvertStencilOp(stencilBackPassDepthPass));
+
+ mCurDepthStencilState.stencilBackFail = stencilBackFail;
+ mCurDepthStencilState.stencilBackPassDepthFail = stencilBackPassDepthFail;
+ mCurDepthStencilState.stencilBackPassDepthPass = stencilBackPassDepthPass;
+}
+
+void StateManager9::setStencilBackWriteMask(GLuint stencilBackWriteMask, bool frontFaceCCW)
+{
+ mRenderer9->getDevice()->SetRenderState(
+ !frontFaceCCW ? D3DRS_STENCILWRITEMASK : D3DRS_CCW_STENCILWRITEMASK, stencilBackWriteMask);
+
+ mCurDepthStencilState.stencilBackWritemask = stencilBackWriteMask;
+}
+
+void StateManager9::setStencilFuncsBack(GLenum stencilBackFunc,
+ GLuint stencilBackMask,
+ GLint stencilBackRef,
+ bool frontFaceCCW,
+ unsigned int maxStencil)
+{
+ IDirect3DDevice9 *device = mRenderer9->getDevice();
+ device->SetRenderState(!frontFaceCCW ? D3DRS_STENCILFUNC : D3DRS_CCW_STENCILFUNC,
+ gl_d3d9::ConvertComparison(stencilBackFunc));
+ device->SetRenderState(!frontFaceCCW ? D3DRS_STENCILREF : D3DRS_CCW_STENCILREF,
+ (stencilBackRef < (int)maxStencil) ? stencilBackRef : maxStencil);
+ device->SetRenderState(!frontFaceCCW ? D3DRS_STENCILMASK : D3DRS_CCW_STENCILMASK,
+ stencilBackMask);
+
+ mCurDepthStencilState.stencilBackFunc = stencilBackFunc;
+ mCurStencilBackRef = stencilBackRef;
+ mCurDepthStencilState.stencilBackMask = stencilBackMask;
+}
+
+void StateManager9::setStencilWriteMask(GLuint stencilWriteMask, bool frontFaceCCW)
+{
+ mRenderer9->getDevice()->SetRenderState(
+ frontFaceCCW ? D3DRS_STENCILWRITEMASK : D3DRS_CCW_STENCILWRITEMASK, stencilWriteMask);
+ mCurDepthStencilState.stencilWritemask = stencilWriteMask;
+}
+
+void StateManager9::setStencilFuncsFront(GLenum stencilFunc,
+ GLuint stencilMask,
+ GLint stencilRef,
+ bool frontFaceCCW,
+ unsigned int maxStencil)
+{
+ IDirect3DDevice9 *device = mRenderer9->getDevice();
+ device->SetRenderState(frontFaceCCW ? D3DRS_STENCILFUNC : D3DRS_CCW_STENCILFUNC,
+ gl_d3d9::ConvertComparison(stencilFunc));
+ device->SetRenderState(frontFaceCCW ? D3DRS_STENCILREF : D3DRS_CCW_STENCILREF,
+ (stencilRef < static_cast<int>(maxStencil)) ? stencilRef : maxStencil);
+ device->SetRenderState(frontFaceCCW ? D3DRS_STENCILMASK : D3DRS_CCW_STENCILMASK, stencilMask);
+
+ mCurDepthStencilState.stencilFunc = stencilFunc;
+ mCurStencilRef = stencilRef;
+ mCurDepthStencilState.stencilMask = stencilMask;
+}
+void StateManager9::setStencilTestEnabled(bool stencilTestEnabled)
+{
+ if (stencilTestEnabled && mCurStencilSize > 0)
+ {
+ mRenderer9->getDevice()->SetRenderState(D3DRS_STENCILENABLE, TRUE);
+ }
+ else
+ {
+ mRenderer9->getDevice()->SetRenderState(D3DRS_STENCILENABLE, FALSE);
+ }
+
+ mCurDepthStencilState.stencilTest = stencilTestEnabled;
+}
+
+void StateManager9::setDepthMask(bool depthMask)
+{
+ mRenderer9->getDevice()->SetRenderState(D3DRS_ZWRITEENABLE, depthMask ? TRUE : FALSE);
+ mCurDepthStencilState.depthMask = depthMask;
+}
+
+// TODO(dianx) one bit for sampleAlphaToCoverage
+void StateManager9::setSampleAlphaToCoverage(bool enabled)
+{
+ if (enabled)
+ {
+ FIXME("Sample alpha to coverage is unimplemented.");
+ }
+}
+
+void StateManager9::setBlendColor(const gl::BlendState &blendState, const gl::ColorF &blendColor)
+{
+ if (!blendState.blend)
+ return;
+
+ if (blendState.sourceBlendRGB != GL_CONSTANT_ALPHA &&
+ blendState.sourceBlendRGB != GL_ONE_MINUS_CONSTANT_ALPHA &&
+ blendState.destBlendRGB != GL_CONSTANT_ALPHA &&
+ blendState.destBlendRGB != GL_ONE_MINUS_CONSTANT_ALPHA)
+ {
+ mRenderer9->getDevice()->SetRenderState(D3DRS_BLENDFACTOR,
+ gl_d3d9::ConvertColor(blendColor));
+ }
+ else
+ {
+ mRenderer9->getDevice()->SetRenderState(
+ D3DRS_BLENDFACTOR,
+ D3DCOLOR_RGBA(gl::unorm<8>(blendColor.alpha), gl::unorm<8>(blendColor.alpha),
+ gl::unorm<8>(blendColor.alpha), gl::unorm<8>(blendColor.alpha)));
+ }
+ mCurBlendColor = blendColor;
+}
+
+void StateManager9::setBlendFuncsEquations(const gl::BlendState &blendState)
+{
+ if (!blendState.blend)
+ return;
+
+ IDirect3DDevice9 *device = mRenderer9->getDevice();
+
+ device->SetRenderState(D3DRS_SRCBLEND, gl_d3d9::ConvertBlendFunc(blendState.sourceBlendRGB));
+ device->SetRenderState(D3DRS_DESTBLEND, gl_d3d9::ConvertBlendFunc(blendState.destBlendRGB));
+ device->SetRenderState(D3DRS_BLENDOP, gl_d3d9::ConvertBlendOp(blendState.blendEquationRGB));
+
+ if (blendState.sourceBlendRGB != blendState.sourceBlendAlpha ||
+ blendState.destBlendRGB != blendState.destBlendAlpha ||
+ blendState.blendEquationRGB != blendState.blendEquationAlpha)
+ {
+ device->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE);
+
+ device->SetRenderState(D3DRS_SRCBLENDALPHA,
+ gl_d3d9::ConvertBlendFunc(blendState.sourceBlendAlpha));
+ device->SetRenderState(D3DRS_DESTBLENDALPHA,
+ gl_d3d9::ConvertBlendFunc(blendState.destBlendAlpha));
+ device->SetRenderState(D3DRS_BLENDOPALPHA,
+ gl_d3d9::ConvertBlendOp(blendState.blendEquationAlpha));
+ }
+ else
+ {
+ device->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, FALSE);
+ }
+
+ mCurBlendState.sourceBlendRGB = blendState.sourceBlendRGB;
+ mCurBlendState.destBlendRGB = blendState.destBlendRGB;
+ mCurBlendState.blendEquationRGB = blendState.blendEquationRGB;
+ mCurBlendState.blendEquationAlpha = blendState.blendEquationAlpha;
+}
+
+void StateManager9::setBlendEnabled(bool enabled)
+{
+ mRenderer9->getDevice()->SetRenderState(D3DRS_ALPHABLENDENABLE, enabled ? TRUE : FALSE);
+ mCurBlendState.blend = enabled;
+}
+
+void StateManager9::setDither(bool dither)
+{
+ mRenderer9->getDevice()->SetRenderState(D3DRS_DITHERENABLE, dither ? TRUE : FALSE);
+ mCurBlendState.dither = dither;
+}
+
+// TODO(dianx) one bit for color mask
+void StateManager9::setColorMask(const gl::Framebuffer *framebuffer,
+ bool red,
+ bool blue,
+ bool green,
+ bool alpha)
+{
+ // Set the color mask
+ bool zeroColorMaskAllowed = mRenderer9->getVendorId() != VENDOR_ID_AMD;
+ // Apparently some ATI cards have a bug where a draw with a zero color
+ // write mask can cause later draws to have incorrect results. Instead,
+ // set a nonzero color write mask but modify the blend state so that no
+ // drawing is done.
+ // http://code.google.com/p/angleproject/issues/detail?id=169
+
+ const gl::FramebufferAttachment *attachment = framebuffer->getFirstColorbuffer();
+ GLenum internalFormat = attachment ? attachment->getInternalFormat() : GL_NONE;
+
+ const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat);
+
+ DWORD colorMask = gl_d3d9::ConvertColorMask(
+ formatInfo.redBits > 0 && red, formatInfo.greenBits > 0 && green,
+ formatInfo.blueBits > 0 && blue, formatInfo.alphaBits > 0 && alpha);
+
+ if (colorMask == 0 && !zeroColorMaskAllowed)
+ {
+ IDirect3DDevice9 *device = mRenderer9->getDevice();
+ // Enable green channel, but set blending so nothing will be drawn.
+ device->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_GREEN);
+ device->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
+
+ device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ZERO);
+ device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);
+ device->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
+ }
+ else
+ {
+ mRenderer9->getDevice()->SetRenderState(D3DRS_COLORWRITEENABLE, colorMask);
+ }
+
+ mCurBlendState.colorMaskRed = red;
+ mCurBlendState.colorMaskGreen = green;
+ mCurBlendState.colorMaskBlue = blue;
+ mCurBlendState.colorMaskAlpha = alpha;
+}
+
+void StateManager9::setSampleMask(unsigned int sampleMask)
+{
+ IDirect3DDevice9 *device = mRenderer9->getDevice();
+ // Set the multisample mask
+ device->SetRenderState(D3DRS_MULTISAMPLEANTIALIAS, TRUE);
+ device->SetRenderState(D3DRS_MULTISAMPLEMASK, static_cast<DWORD>(sampleMask));
+
+ mCurSampleMask = sampleMask;
+}
+
+void StateManager9::setCullMode(bool cullFace, GLenum cullMode, GLenum frontFace)
+{
+ if (cullFace)
+ {
+ mRenderer9->getDevice()->SetRenderState(D3DRS_CULLMODE,
+ gl_d3d9::ConvertCullMode(cullMode, frontFace));
+ }
+ else
+ {
+ mRenderer9->getDevice()->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
+ }
+
+ mCurRasterState.cullFace = cullFace;
+ mCurRasterState.cullMode = cullMode;
+ mCurRasterState.frontFace = frontFace;
+}
+
+void StateManager9::setDepthBias(bool polygonOffsetFill,
+ GLfloat polygonOffsetFactor,
+ GLfloat polygonOffsetUnits)
+{
+ if (polygonOffsetFill)
+ {
+ if (mCurDepthSize > 0)
+ {
+ IDirect3DDevice9 *device = mRenderer9->getDevice();
+ device->SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS, *(DWORD *)&polygonOffsetFactor);
+
+ float depthBias = ldexp(polygonOffsetUnits, -static_cast<int>(mCurDepthSize));
+ device->SetRenderState(D3DRS_DEPTHBIAS, *(DWORD *)&depthBias);
+ }
+ }
+ else
+ {
+ IDirect3DDevice9 *device = mRenderer9->getDevice();
+ device->SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS, 0);
+ device->SetRenderState(D3DRS_DEPTHBIAS, 0);
+ }
+
+ mCurRasterState.polygonOffsetFill = polygonOffsetFill;
+ mCurRasterState.polygonOffsetFactor = polygonOffsetFactor;
+ mCurRasterState.polygonOffsetUnits = polygonOffsetUnits;
+}
+
+void StateManager9::updateDepthSizeIfChanged(bool depthStencilInitialized, unsigned int depthSize)
+{
+ if (!depthStencilInitialized || depthSize != mCurDepthSize)
+ {
+ mCurDepthSize = depthSize;
+ forceSetRasterState();
+ }
+}
+} // namespace rx
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/StateManager9.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/StateManager9.h
new file mode 100644
index 0000000000..d8c1eb9812
--- /dev/null
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/StateManager9.h
@@ -0,0 +1,206 @@
+//
+// 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.
+//
+
+// StateManager9.h: Defines a class for caching D3D9 state
+
+#ifndef LIBANGLE_RENDERER_D3D9_STATEMANAGER9_H_
+#define LIBANGLE_RENDERER_D3D9_STATEMANAGER9_H_
+
+#include "libANGLE/angletypes.h"
+#include "libANGLE/Data.h"
+#include "libANGLE/State.h"
+#include "libANGLE/renderer/d3d/RendererD3D.h"
+
+namespace rx
+{
+
+class Renderer9;
+
+struct dx_VertexConstants9
+{
+ float depthRange[4];
+ float viewAdjust[4];
+ float viewCoords[4];
+};
+
+struct dx_PixelConstants9
+{
+ float depthRange[4];
+ float viewCoords[4];
+ float depthFront[4];
+};
+
+class StateManager9 final : angle::NonCopyable
+{
+ public:
+ StateManager9(Renderer9 *renderer9);
+ ~StateManager9();
+
+ void syncState(const gl::State &state, const gl::State::DirtyBits &dirtyBits);
+
+ gl::Error setBlendDepthRasterStates(const gl::State &glState, unsigned int sampleMask);
+ void setScissorState(const gl::Rectangle &scissor, bool enabled);
+ void setViewportState(const gl::Caps *caps,
+ const gl::Rectangle &viewport,
+ float zNear,
+ float zFar,
+ GLenum drawMode,
+ GLenum frontFace,
+ bool ignoreViewport);
+
+ void setShaderConstants();
+
+ void forceSetBlendState();
+ void forceSetRasterState();
+ void forceSetDepthStencilState();
+ void forceSetScissorState();
+ void forceSetViewportState();
+ void forceSetDXUniformsState();
+
+ void updateDepthSizeIfChanged(bool depthStencilInitialized, unsigned int depthSize);
+ void updateStencilSizeIfChanged(bool depthStencilInitialized, unsigned int stencilSize);
+
+ void setRenderTargetBounds(size_t width, size_t height);
+
+ int getRenderTargetWidth() const { return mRenderTargetBounds.width; }
+ int getRenderTargetHeight() const { return mRenderTargetBounds.height; }
+
+ void resetDirtyBits() { mDirtyBits.reset(); }
+
+ private:
+ // Blend state functions
+ void setBlendEnabled(bool enabled);
+ void setBlendColor(const gl::BlendState &blendState, const gl::ColorF &blendColor);
+ void setBlendFuncsEquations(const gl::BlendState &blendState);
+ void setColorMask(const gl::Framebuffer *framebuffer,
+ bool red,
+ bool blue,
+ bool green,
+ bool alpha);
+ void setSampleAlphaToCoverage(bool enabled);
+ void setDither(bool dither);
+ void setSampleMask(unsigned int sampleMask);
+
+ // Current raster state functions
+ void setCullMode(bool cullFace, GLenum cullMode, GLenum frontFace);
+ void setDepthBias(bool polygonOffsetFill,
+ GLfloat polygonOffsetFactor,
+ GLfloat polygonOffsetUnits);
+
+ // Depth stencil state functions
+ void setStencilOpsFront(GLenum stencilFail,
+ GLenum stencilPassDepthFail,
+ GLenum stencilPassDepthPass,
+ bool frontFaceCCW);
+ void setStencilOpsBack(GLenum stencilBackFail,
+ GLenum stencilBackPassDepthFail,
+ GLenum stencilBackPassDepthPass,
+ bool frontFaceCCW);
+ void setStencilBackWriteMask(GLuint stencilBackWriteMask, bool frontFaceCCW);
+ void setDepthFunc(bool depthTest, GLenum depthFunc);
+ void setStencilTestEnabled(bool enabled);
+ void setDepthMask(bool depthMask);
+ void setStencilFuncsFront(GLenum stencilFunc,
+ GLuint stencilMask,
+ GLint stencilRef,
+ bool frontFaceCCW,
+ unsigned int maxStencil);
+ void setStencilFuncsBack(GLenum stencilBackFunc,
+ GLuint stencilBackMask,
+ GLint stencilBackRef,
+ bool frontFaceCCW,
+ unsigned int maxStencil);
+ void setStencilWriteMask(GLuint stencilWriteMask, bool frontFaceCCW);
+
+ void setScissorEnabled(bool scissorEnabled);
+ void setScissorRect(const gl::Rectangle &scissor, bool enabled);
+
+ enum DirtyBitType
+ {
+ // Blend dirty bits
+ DIRTY_BIT_BLEND_ENABLED,
+ DIRTY_BIT_BLEND_COLOR,
+ DIRTY_BIT_BLEND_FUNCS_EQUATIONS,
+ DIRTY_BIT_SAMPLE_ALPHA_TO_COVERAGE,
+ DIRTY_BIT_COLOR_MASK,
+ DIRTY_BIT_DITHER,
+ DIRTY_BIT_SAMPLE_MASK,
+
+ // Rasterizer dirty bits
+ DIRTY_BIT_CULL_MODE,
+ DIRTY_BIT_DEPTH_BIAS,
+
+ // Depth stencil dirty bits
+ DIRTY_BIT_STENCIL_DEPTH_MASK,
+ DIRTY_BIT_STENCIL_DEPTH_FUNC,
+ DIRTY_BIT_STENCIL_TEST_ENABLED,
+ DIRTY_BIT_STENCIL_FUNCS_FRONT,
+ DIRTY_BIT_STENCIL_FUNCS_BACK,
+ DIRTY_BIT_STENCIL_WRITEMASK_FRONT,
+ DIRTY_BIT_STENCIL_WRITEMASK_BACK,
+ DIRTY_BIT_STENCIL_OPS_FRONT,
+ DIRTY_BIT_STENCIL_OPS_BACK,
+
+ // Scissor dirty bits
+ DIRTY_BIT_SCISSOR_ENABLED,
+ DIRTY_BIT_SCISSOR_RECT,
+
+ // Viewport dirty bits
+ DIRTY_BIT_VIEWPORT,
+
+ DIRTY_BIT_MAX
+ };
+
+ typedef std::bitset<DIRTY_BIT_MAX> DirtyBits;
+
+ // Currently applied blend state
+ gl::BlendState mCurBlendState;
+ gl::ColorF mCurBlendColor;
+ unsigned int mCurSampleMask;
+ DirtyBits mBlendStateDirtyBits;
+
+ // Currently applied raster state
+ gl::RasterizerState mCurRasterState;
+ unsigned int mCurDepthSize;
+ DirtyBits mRasterizerStateDirtyBits;
+
+ // Currently applied depth stencil state
+ gl::DepthStencilState mCurDepthStencilState;
+ int mCurStencilRef;
+ int mCurStencilBackRef;
+ bool mCurFrontFaceCCW;
+ unsigned int mCurStencilSize;
+ DirtyBits mDepthStencilStateDirtyBits;
+
+ // Currently applied scissor states
+ gl::Rectangle mCurScissorRect;
+ bool mCurScissorEnabled;
+ gl::Extents mRenderTargetBounds;
+ DirtyBits mScissorStateDirtyBits;
+
+ // Currently applied viewport states
+ bool mForceSetViewport;
+ gl::Rectangle mCurViewport;
+ float mCurNear;
+ float mCurFar;
+ float mCurDepthFront;
+ bool mCurIgnoreViewport;
+
+ dx_VertexConstants9 mVertexConstants;
+ dx_PixelConstants9 mPixelConstants;
+ bool mDxUniformsDirty;
+
+ // FIXME: Unsupported by D3D9
+ static const D3DRENDERSTATETYPE D3DRS_CCW_STENCILREF = D3DRS_STENCILREF;
+ static const D3DRENDERSTATETYPE D3DRS_CCW_STENCILMASK = D3DRS_STENCILMASK;
+ static const D3DRENDERSTATETYPE D3DRS_CCW_STENCILWRITEMASK = D3DRS_STENCILWRITEMASK;
+
+ Renderer9 *mRenderer9;
+ DirtyBits mDirtyBits;
+};
+
+} // namespace rx
+#endif // LIBANGLE_RENDERER_D3D9_STATEMANAGER9_H_
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/SwapChain9.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/SwapChain9.cpp
index 1620668166..be6a9c424c 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/SwapChain9.cpp
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/SwapChain9.cpp
@@ -15,21 +15,26 @@
namespace rx
{
-SwapChain9::SwapChain9(Renderer9 *renderer, NativeWindow nativeWindow, HANDLE shareHandle,
- GLenum backBufferFormat, GLenum depthBufferFormat)
- : mRenderer(renderer),
- SwapChainD3D(nativeWindow, shareHandle, backBufferFormat, depthBufferFormat),
+SwapChain9::SwapChain9(Renderer9 *renderer,
+ NativeWindow nativeWindow,
+ HANDLE shareHandle,
+ GLenum backBufferFormat,
+ GLenum depthBufferFormat,
+ EGLint orientation)
+ : SwapChainD3D(nativeWindow, shareHandle, backBufferFormat, depthBufferFormat),
+ mRenderer(renderer),
+ mWidth(-1),
+ mHeight(-1),
+ mSwapInterval(-1),
+ mSwapChain(nullptr),
+ mBackBuffer(nullptr),
+ mRenderTarget(nullptr),
+ mDepthStencil(nullptr),
+ mOffscreenTexture(nullptr),
mColorRenderTarget(this, false),
mDepthStencilRenderTarget(this, true)
{
- mSwapChain = NULL;
- mBackBuffer = NULL;
- mDepthStencil = NULL;
- mRenderTarget = NULL;
- mOffscreenTexture = NULL;
- mWidth = -1;
- mHeight = -1;
- mSwapInterval = -1;
+ ASSERT(orientation == 0);
}
SwapChain9::~SwapChain9()
@@ -104,7 +109,7 @@ EGLint SwapChain9::reset(int backbufferWidth, int backbufferHeight, EGLint swapI
pShareHandle = &mShareHandle;
}
- const d3d9::TextureFormat &backBufferd3dFormatInfo = d3d9::GetTextureFormatInfo(mBackBufferFormat);
+ const d3d9::TextureFormat &backBufferd3dFormatInfo = d3d9::GetTextureFormatInfo(mOffscreenRenderTargetFormat);
result = device->CreateTexture(backbufferWidth, backbufferHeight, 1, D3DUSAGE_RENDERTARGET,
backBufferd3dFormatInfo.texFormat, D3DPOOL_DEFAULT, &mOffscreenTexture,
pShareHandle);
@@ -286,7 +291,7 @@ EGLint SwapChain9::swapRect(EGLint x, EGLint y, EGLint width, EGLint height)
device->SetStreamSourceFreq(streamIndex, 1);
}
- D3DVIEWPORT9 viewport = {0, 0, mWidth, mHeight, 0.0f, 1.0f};
+ D3DVIEWPORT9 viewport = {0, 0, static_cast<DWORD>(mWidth), static_cast<DWORD>(mHeight), 0.0f, 1.0f};
device->SetViewport(&viewport);
float x1 = x - 0.5f;
@@ -312,8 +317,8 @@ EGLint SwapChain9::swapRect(EGLint x, EGLint y, EGLint width, EGLint height)
RECT rect =
{
- x, mHeight - y - height,
- x + width, mHeight - y
+ static_cast<LONG>(x), static_cast<LONG>(mHeight - y - height),
+ static_cast<LONG>(x + width), static_cast<LONG>(mHeight - y)
};
HRESULT result = mSwapChain->Present(&rect, &rect, NULL, NULL, 0);
@@ -384,10 +389,10 @@ IDirect3DTexture9 *SwapChain9::getOffscreenTexture()
return mOffscreenTexture;
}
-SwapChain9 *SwapChain9::makeSwapChain9(SwapChainD3D *swapChain)
+void *SwapChain9::getKeyedMutex()
{
- ASSERT(HAS_DYNAMIC_TYPE(SwapChain9*, swapChain));
- return static_cast<SwapChain9*>(swapChain);
+ UNREACHABLE();
+ return nullptr;
}
void SwapChain9::recreate()
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/SwapChain9.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/SwapChain9.h
index 81ac08ca7b..55a700c2d6 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/SwapChain9.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/SwapChain9.h
@@ -20,8 +20,12 @@ class Renderer9;
class SwapChain9 : public SwapChainD3D
{
public:
- SwapChain9(Renderer9 *renderer, NativeWindow nativeWindow, HANDLE shareHandle,
- GLenum backBufferFormat, GLenum depthBufferFormat);
+ SwapChain9(Renderer9 *renderer,
+ NativeWindow nativeWindow,
+ HANDLE shareHandle,
+ GLenum backBufferFormat,
+ GLenum depthBufferFormat,
+ EGLint orientation);
virtual ~SwapChain9();
EGLint resize(EGLint backbufferWidth, EGLint backbufferHeight);
@@ -39,14 +43,14 @@ class SwapChain9 : public SwapChainD3D
EGLint getWidth() const { return mWidth; }
EGLint getHeight() const { return mHeight; }
- static SwapChain9 *makeSwapChain9(SwapChainD3D *swapChain);
+ void *getKeyedMutex() override;
private:
void release();
Renderer9 *mRenderer;
- EGLint mHeight;
EGLint mWidth;
+ EGLint mHeight;
EGLint mSwapInterval;
IDirect3DSwapChain9 *mSwapChain;
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/TextureStorage9.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/TextureStorage9.cpp
index 139cb3eb08..b28d5076b5 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/TextureStorage9.cpp
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/TextureStorage9.cpp
@@ -9,14 +9,16 @@
// D3D9 texture.
#include "libANGLE/renderer/d3d/d3d9/TextureStorage9.h"
-#include "libANGLE/renderer/d3d/d3d9/Renderer9.h"
-#include "libANGLE/renderer/d3d/d3d9/SwapChain9.h"
-#include "libANGLE/renderer/d3d/d3d9/RenderTarget9.h"
-#include "libANGLE/renderer/d3d/d3d9/renderer9_utils.h"
-#include "libANGLE/renderer/d3d/d3d9/formatutils9.h"
-#include "libANGLE/renderer/d3d/TextureD3D.h"
+
#include "libANGLE/formatutils.h"
#include "libANGLE/Texture.h"
+#include "libANGLE/renderer/d3d/EGLImageD3D.h"
+#include "libANGLE/renderer/d3d/TextureD3D.h"
+#include "libANGLE/renderer/d3d/d3d9/formatutils9.h"
+#include "libANGLE/renderer/d3d/d3d9/renderer9_utils.h"
+#include "libANGLE/renderer/d3d/d3d9/Renderer9.h"
+#include "libANGLE/renderer/d3d/d3d9/RenderTarget9.h"
+#include "libANGLE/renderer/d3d/d3d9/SwapChain9.h"
namespace rx
{
@@ -27,7 +29,7 @@ TextureStorage9::TextureStorage9(Renderer9 *renderer, DWORD usage)
mTextureHeight(0),
mInternalFormat(GL_NONE),
mTextureFormat(D3DFMT_UNKNOWN),
- mRenderer(Renderer9::makeRenderer9(renderer)),
+ mRenderer(renderer),
mD3DUsage(usage),
mD3DPool(mRenderer->getTexturePool(usage))
{
@@ -37,12 +39,6 @@ TextureStorage9::~TextureStorage9()
{
}
-TextureStorage9 *TextureStorage9::makeTextureStorage9(TextureStorage *storage)
-{
- ASSERT(HAS_DYNAMIC_TYPE(TextureStorage9*, storage));
- return static_cast<TextureStorage9*>(storage);
-}
-
DWORD TextureStorage9::GetTextureUsage(GLenum internalformat, bool renderTarget)
{
DWORD d3dusage = 0;
@@ -72,6 +68,11 @@ bool TextureStorage9::isManaged() const
return (mD3DPool == D3DPOOL_MANAGED);
}
+bool TextureStorage9::supportsNativeMipmapFunction() const
+{
+ return false;
+}
+
D3DPOOL TextureStorage9::getPool() const
{
return mD3DPool;
@@ -89,7 +90,7 @@ int TextureStorage9::getTopLevel() const
int TextureStorage9::getLevelCount() const
{
- return mMipLevels - mTopLevel;
+ return static_cast<int>(mMipLevels) - mTopLevel;
}
gl::Error TextureStorage9::setData(const gl::ImageIndex &index, ImageD3D *image, const gl::Box *destBox, GLenum type,
@@ -106,7 +107,7 @@ TextureStorage9_2D::TextureStorage9_2D(Renderer9 *renderer, SwapChain9 *swapchai
mTexture = surfaceTexture;
mMipLevels = surfaceTexture->GetLevelCount();
- mInternalFormat = swapchain->GetBackBufferInternalFormat();
+ mInternalFormat = swapchain->GetRenderTargetInternalFormat();
D3DSURFACE_DESC surfaceDesc;
surfaceTexture->GetLevelDesc(0, &surfaceDesc);
@@ -114,16 +115,13 @@ TextureStorage9_2D::TextureStorage9_2D(Renderer9 *renderer, SwapChain9 *swapchai
mTextureHeight = surfaceDesc.Height;
mTextureFormat = surfaceDesc.Format;
- mRenderTarget = NULL;
-
- initializeSerials(1, 1);
+ mRenderTargets.resize(mMipLevels, nullptr);
}
TextureStorage9_2D::TextureStorage9_2D(Renderer9 *renderer, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels)
: TextureStorage9(renderer, GetTextureUsage(internalformat, renderTarget))
{
mTexture = NULL;
- mRenderTarget = NULL;
mInternalFormat = internalformat;
@@ -135,25 +133,28 @@ TextureStorage9_2D::TextureStorage9_2D(Renderer9 *renderer, GLenum internalforma
mTextureHeight = height;
mMipLevels = mTopLevel + levels;
- initializeSerials(getLevelCount(), 1);
+ mRenderTargets.resize(levels, nullptr);
}
TextureStorage9_2D::~TextureStorage9_2D()
{
SafeRelease(mTexture);
- SafeDelete(mRenderTarget);
-}
-
-TextureStorage9_2D *TextureStorage9_2D::makeTextureStorage9_2D(TextureStorage *storage)
-{
- ASSERT(HAS_DYNAMIC_TYPE(TextureStorage9_2D*, storage));
- return static_cast<TextureStorage9_2D*>(storage);
+ for (auto &renderTarget : mRenderTargets)
+ {
+ SafeDelete(renderTarget);
+ }
}
// Increments refcount on surface.
// caller must Release() the returned surface
-gl::Error TextureStorage9_2D::getSurfaceLevel(int level, bool dirty, IDirect3DSurface9 **outSurface)
+gl::Error TextureStorage9_2D::getSurfaceLevel(GLenum target,
+ int level,
+ bool dirty,
+ IDirect3DSurface9 **outSurface)
{
+ ASSERT(target == GL_TEXTURE_2D);
+ UNUSED_ASSERTION_VARIABLE(target);
+
IDirect3DBaseTexture9 *baseTexture = NULL;
gl::Error error = getBaseTexture(&baseTexture);
if (error.isError())
@@ -180,36 +181,52 @@ gl::Error TextureStorage9_2D::getSurfaceLevel(int level, bool dirty, IDirect3DSu
return gl::Error(GL_NO_ERROR);
}
-gl::Error TextureStorage9_2D::getRenderTarget(const gl::ImageIndex &/*index*/, RenderTargetD3D **outRT)
+gl::Error TextureStorage9_2D::getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT)
{
- if (!mRenderTarget && isRenderTarget())
+ ASSERT(index.mipIndex < getLevelCount());
+
+ if (!mRenderTargets[index.mipIndex] && isRenderTarget())
{
+ IDirect3DBaseTexture9 *baseTexture = NULL;
+ gl::Error error = getBaseTexture(&baseTexture);
+ if (error.isError())
+ {
+ return error;
+ }
+
IDirect3DSurface9 *surface = NULL;
- gl::Error error = getSurfaceLevel(0, false, &surface);
+ error = getSurfaceLevel(GL_TEXTURE_2D, index.mipIndex, false, &surface);
if (error.isError())
{
return error;
}
- mRenderTarget = new TextureRenderTarget9(surface, mInternalFormat, mTextureWidth, mTextureHeight, 1, 0);
+ size_t textureMipLevel = mTopLevel + index.mipIndex;
+ size_t mipWidth = std::max<size_t>(mTextureWidth >> textureMipLevel, 1u);
+ size_t mipHeight = std::max<size_t>(mTextureHeight >> textureMipLevel, 1u);
+
+ baseTexture->AddRef();
+ mRenderTargets[index.mipIndex] = new TextureRenderTarget9(
+ baseTexture, textureMipLevel, surface, mInternalFormat, static_cast<GLsizei>(mipWidth),
+ static_cast<GLsizei>(mipHeight), 1, 0);
}
ASSERT(outRT);
- *outRT = mRenderTarget;
+ *outRT = mRenderTargets[index.mipIndex];
return gl::Error(GL_NO_ERROR);
}
gl::Error TextureStorage9_2D::generateMipmap(const gl::ImageIndex &sourceIndex, const gl::ImageIndex &destIndex)
{
IDirect3DSurface9 *upper = NULL;
- gl::Error error = getSurfaceLevel(sourceIndex.mipIndex, false, &upper);
+ gl::Error error = getSurfaceLevel(GL_TEXTURE_2D, sourceIndex.mipIndex, false, &upper);
if (error.isError())
{
return error;
}
IDirect3DSurface9 *lower = NULL;
- error = getSurfaceLevel(destIndex.mipIndex, true, &lower);
+ error = getSurfaceLevel(GL_TEXTURE_2D, destIndex.mipIndex, true, &lower);
if (error.isError())
{
SafeRelease(upper);
@@ -234,8 +251,10 @@ gl::Error TextureStorage9_2D::getBaseTexture(IDirect3DBaseTexture9 **outTexture)
ASSERT(mMipLevels > 0);
IDirect3DDevice9 *device = mRenderer->getDevice();
- HRESULT result = device->CreateTexture(mTextureWidth, mTextureHeight, mMipLevels, getUsage(), mTextureFormat,
- getPool(), &mTexture, NULL);
+ HRESULT result = device->CreateTexture(static_cast<unsigned int>(mTextureWidth),
+ static_cast<unsigned int>(mTextureHeight),
+ static_cast<unsigned int>(mMipLevels), getUsage(),
+ mTextureFormat, getPool(), &mTexture, NULL);
if (FAILED(result))
{
@@ -252,20 +271,20 @@ gl::Error TextureStorage9_2D::copyToStorage(TextureStorage *destStorage)
{
ASSERT(destStorage);
- TextureStorage9_2D *dest9 = TextureStorage9_2D::makeTextureStorage9_2D(destStorage);
+ TextureStorage9_2D *dest9 = GetAs<TextureStorage9_2D>(destStorage);
int levels = getLevelCount();
for (int i = 0; i < levels; ++i)
{
IDirect3DSurface9 *srcSurf = NULL;
- gl::Error error = getSurfaceLevel(i, false, &srcSurf);
+ gl::Error error = getSurfaceLevel(GL_TEXTURE_2D, i, false, &srcSurf);
if (error.isError())
{
return error;
}
IDirect3DSurface9 *dstSurf = NULL;
- error = dest9->getSurfaceLevel(i, true, &dstSurf);
+ error = dest9->getSurfaceLevel(GL_TEXTURE_2D, i, true, &dstSurf);
if (error.isError())
{
SafeRelease(srcSurf);
@@ -286,6 +305,131 @@ gl::Error TextureStorage9_2D::copyToStorage(TextureStorage *destStorage)
return gl::Error(GL_NO_ERROR);
}
+TextureStorage9_EGLImage::TextureStorage9_EGLImage(Renderer9 *renderer, EGLImageD3D *image)
+ : TextureStorage9(renderer, D3DUSAGE_RENDERTARGET), mImage(image)
+{
+ RenderTargetD3D *renderTargetD3D = nullptr;
+ mImage->getRenderTarget(&renderTargetD3D);
+
+ RenderTarget9 *renderTarget9 = GetAs<RenderTarget9>(renderTargetD3D);
+
+ mInternalFormat = renderTarget9->getInternalFormat();
+ mTextureFormat = renderTarget9->getD3DFormat();
+ mTextureWidth = renderTarget9->getWidth();
+ mTextureHeight = renderTarget9->getHeight();
+ mTopLevel = static_cast<int>(renderTarget9->getTextureLevel());
+ mMipLevels = mTopLevel + 1;
+}
+
+TextureStorage9_EGLImage::~TextureStorage9_EGLImage()
+{
+}
+
+gl::Error TextureStorage9_EGLImage::getSurfaceLevel(GLenum target,
+ int level,
+ bool,
+ IDirect3DSurface9 **outSurface)
+{
+ ASSERT(target == GL_TEXTURE_2D);
+ ASSERT(level == 0);
+ UNUSED_ASSERTION_VARIABLE(target);
+ UNUSED_ASSERTION_VARIABLE(level);
+
+ RenderTargetD3D *renderTargetD3D = nullptr;
+ gl::Error error = mImage->getRenderTarget(&renderTargetD3D);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ RenderTarget9 *renderTarget9 = GetAs<RenderTarget9>(renderTargetD3D);
+
+ *outSurface = renderTarget9->getSurface();
+ return gl::Error(GL_NO_ERROR);
+}
+
+gl::Error TextureStorage9_EGLImage::getRenderTarget(const gl::ImageIndex &index,
+ RenderTargetD3D **outRT)
+{
+ ASSERT(!index.hasLayer());
+ ASSERT(index.mipIndex == 0);
+ UNUSED_ASSERTION_VARIABLE(index);
+
+ return mImage->getRenderTarget(outRT);
+}
+
+gl::Error TextureStorage9_EGLImage::getBaseTexture(IDirect3DBaseTexture9 **outTexture)
+{
+ RenderTargetD3D *renderTargetD3D = nullptr;
+ gl::Error error = mImage->getRenderTarget(&renderTargetD3D);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ RenderTarget9 *renderTarget9 = GetAs<RenderTarget9>(renderTargetD3D);
+ *outTexture = renderTarget9->getTexture();
+ ASSERT(*outTexture != nullptr);
+
+ return gl::Error(GL_NO_ERROR);
+}
+
+gl::Error TextureStorage9_EGLImage::generateMipmap(const gl::ImageIndex &, const gl::ImageIndex &)
+{
+ UNREACHABLE();
+ return gl::Error(GL_INVALID_OPERATION);
+}
+
+gl::Error TextureStorage9_EGLImage::copyToStorage(TextureStorage *destStorage)
+{
+ ASSERT(destStorage);
+ ASSERT(getLevelCount() == 1);
+
+ TextureStorage9 *dest9 = GetAs<TextureStorage9>(destStorage);
+
+ IDirect3DBaseTexture9 *destBaseTexture9 = nullptr;
+ gl::Error error = dest9->getBaseTexture(&destBaseTexture9);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ IDirect3DTexture9 *destTexture9 = static_cast<IDirect3DTexture9 *>(destBaseTexture9);
+
+ IDirect3DSurface9 *destSurface = nullptr;
+ HRESULT result = destTexture9->GetSurfaceLevel(destStorage->getTopLevel(), &destSurface);
+ if (FAILED(result))
+ {
+ return gl::Error(GL_OUT_OF_MEMORY,
+ "Failed to get the surface from a texture, result: 0x%X.", result);
+ }
+
+ RenderTargetD3D *sourceRenderTarget = nullptr;
+ error = mImage->getRenderTarget(&sourceRenderTarget);
+ if (error.isError())
+ {
+ SafeRelease(destSurface);
+ return error;
+ }
+
+ RenderTarget9 *sourceRenderTarget9 = GetAs<RenderTarget9>(sourceRenderTarget);
+ error =
+ mRenderer->copyToRenderTarget(destSurface, sourceRenderTarget9->getSurface(), isManaged());
+ if (error.isError())
+ {
+ SafeRelease(destSurface);
+ return error;
+ }
+
+ if (destStorage->getTopLevel() != 0)
+ {
+ destTexture9->AddDirtyRect(nullptr);
+ }
+
+ SafeRelease(destSurface);
+ return gl::Error(GL_NO_ERROR);
+}
+
TextureStorage9_Cube::TextureStorage9_Cube(Renderer9 *renderer, GLenum internalformat, bool renderTarget, int size, int levels, bool hintLevelZeroOnly)
: TextureStorage9(renderer, GetTextureUsage(internalformat, renderTarget))
{
@@ -305,8 +449,6 @@ TextureStorage9_Cube::TextureStorage9_Cube(Renderer9 *renderer, GLenum internalf
mTextureWidth = size;
mTextureHeight = size;
mMipLevels = mTopLevel + levels;
-
- initializeSerials(getLevelCount() * CUBE_FACE_COUNT, CUBE_FACE_COUNT);
}
TextureStorage9_Cube::~TextureStorage9_Cube()
@@ -319,15 +461,12 @@ TextureStorage9_Cube::~TextureStorage9_Cube()
}
}
-TextureStorage9_Cube *TextureStorage9_Cube::makeTextureStorage9_Cube(TextureStorage *storage)
-{
- ASSERT(HAS_DYNAMIC_TYPE(TextureStorage9_Cube*, storage));
- return static_cast<TextureStorage9_Cube*>(storage);
-}
-
// Increments refcount on surface.
// caller must Release() the returned surface
-gl::Error TextureStorage9_Cube::getCubeMapSurface(GLenum faceTarget, int level, bool dirty, IDirect3DSurface9 **outSurface)
+gl::Error TextureStorage9_Cube::getSurfaceLevel(GLenum target,
+ int level,
+ bool dirty,
+ IDirect3DSurface9 **outSurface)
{
IDirect3DBaseTexture9 *baseTexture = NULL;
gl::Error error = getBaseTexture(&baseTexture);
@@ -338,8 +477,8 @@ gl::Error TextureStorage9_Cube::getCubeMapSurface(GLenum faceTarget, int level,
IDirect3DCubeTexture9 *texture = static_cast<IDirect3DCubeTexture9*>(baseTexture);
- D3DCUBEMAP_FACES face = gl_d3d9::ConvertCubeFace(faceTarget);
- HRESULT result = texture->GetCubeMapSurface(face, level + mTopLevel, outSurface);
+ D3DCUBEMAP_FACES face = gl_d3d9::ConvertCubeFace(target);
+ HRESULT result = texture->GetCubeMapSurface(face, level, outSurface);
ASSERT(SUCCEEDED(result));
if (FAILED(result))
@@ -364,14 +503,25 @@ gl::Error TextureStorage9_Cube::getRenderTarget(const gl::ImageIndex &index, Ren
if (mRenderTarget[index.layerIndex] == NULL && isRenderTarget())
{
+ IDirect3DBaseTexture9 *baseTexture = NULL;
+ gl::Error error = getBaseTexture(&baseTexture);
+ if (error.isError())
+ {
+ return error;
+ }
+
IDirect3DSurface9 *surface = NULL;
- gl::Error error = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + index.layerIndex, 0, false, &surface);
+ error = getSurfaceLevel(GL_TEXTURE_CUBE_MAP_POSITIVE_X + index.layerIndex,
+ mTopLevel + index.mipIndex, false, &surface);
if (error.isError())
{
return error;
}
- mRenderTarget[index.layerIndex] = new TextureRenderTarget9(surface, mInternalFormat, mTextureWidth, mTextureHeight, 1, 0);
+ baseTexture->AddRef();
+ mRenderTarget[index.layerIndex] = new TextureRenderTarget9(
+ baseTexture, mTopLevel + index.mipIndex, surface, mInternalFormat,
+ static_cast<GLsizei>(mTextureWidth), static_cast<GLsizei>(mTextureHeight), 1, 0);
}
*outRT = mRenderTarget[index.layerIndex];
@@ -381,14 +531,14 @@ gl::Error TextureStorage9_Cube::getRenderTarget(const gl::ImageIndex &index, Ren
gl::Error TextureStorage9_Cube::generateMipmap(const gl::ImageIndex &sourceIndex, const gl::ImageIndex &destIndex)
{
IDirect3DSurface9 *upper = NULL;
- gl::Error error = getCubeMapSurface(sourceIndex.type, sourceIndex.mipIndex, false, &upper);
+ gl::Error error = getSurfaceLevel(sourceIndex.type, sourceIndex.mipIndex, false, &upper);
if (error.isError())
{
return error;
}
IDirect3DSurface9 *lower = NULL;
- error = getCubeMapSurface(destIndex.type, destIndex.mipIndex, true, &lower);
+ error = getSurfaceLevel(destIndex.type, destIndex.mipIndex, true, &lower);
if (error.isError())
{
SafeRelease(upper);
@@ -414,8 +564,9 @@ gl::Error TextureStorage9_Cube::getBaseTexture(IDirect3DBaseTexture9 **outTextur
ASSERT(mTextureWidth == mTextureHeight);
IDirect3DDevice9 *device = mRenderer->getDevice();
- HRESULT result = device->CreateCubeTexture(mTextureWidth, mMipLevels, getUsage(), mTextureFormat, getPool(),
- &mTexture, NULL);
+ HRESULT result = device->CreateCubeTexture(
+ static_cast<unsigned int>(mTextureWidth), static_cast<unsigned int>(mMipLevels),
+ getUsage(), mTextureFormat, getPool(), &mTexture, NULL);
if (FAILED(result))
{
@@ -432,7 +583,7 @@ gl::Error TextureStorage9_Cube::copyToStorage(TextureStorage *destStorage)
{
ASSERT(destStorage);
- TextureStorage9_Cube *dest9 = TextureStorage9_Cube::makeTextureStorage9_Cube(destStorage);
+ TextureStorage9_Cube *dest9 = GetAs<TextureStorage9_Cube>(destStorage);
int levels = getLevelCount();
for (int f = 0; f < CUBE_FACE_COUNT; f++)
@@ -440,14 +591,15 @@ gl::Error TextureStorage9_Cube::copyToStorage(TextureStorage *destStorage)
for (int i = 0; i < levels; i++)
{
IDirect3DSurface9 *srcSurf = NULL;
- gl::Error error = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i, false, &srcSurf);
+ gl::Error error =
+ getSurfaceLevel(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i, false, &srcSurf);
if (error.isError())
{
return error;
}
IDirect3DSurface9 *dstSurf = NULL;
- error = dest9->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i, true, &dstSurf);
+ error = dest9->getSurfaceLevel(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i, true, &dstSurf);
if (error.isError())
{
SafeRelease(srcSurf);
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/TextureStorage9.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/TextureStorage9.h
index 5cc06f07b1..50e63a6f14 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/TextureStorage9.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/TextureStorage9.h
@@ -16,6 +16,7 @@
namespace rx
{
+class EGLImageD3D;
class Renderer9;
class SwapChain9;
class RenderTargetD3D;
@@ -26,19 +27,22 @@ class TextureStorage9 : public TextureStorage
public:
virtual ~TextureStorage9();
- static TextureStorage9 *makeTextureStorage9(TextureStorage *storage);
-
static DWORD GetTextureUsage(GLenum internalformat, bool renderTarget);
D3DPOOL getPool() const;
DWORD getUsage() const;
+ virtual gl::Error getSurfaceLevel(GLenum target,
+ int level,
+ bool dirty,
+ IDirect3DSurface9 **outSurface) = 0;
virtual gl::Error getBaseTexture(IDirect3DBaseTexture9 **outTexture) = 0;
virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT) = 0;
virtual int getTopLevel() const;
virtual bool isRenderTarget() const;
virtual bool isManaged() const;
+ bool supportsNativeMipmapFunction() const override;
virtual int getLevelCount() const;
virtual gl::Error setData(const gl::ImageIndex &index, ImageD3D *image, const gl::Box *destBox, GLenum type,
@@ -68,9 +72,10 @@ class TextureStorage9_2D : public TextureStorage9
TextureStorage9_2D(Renderer9 *renderer, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels);
virtual ~TextureStorage9_2D();
- static TextureStorage9_2D *makeTextureStorage9_2D(TextureStorage *storage);
-
- gl::Error getSurfaceLevel(int level, bool dirty, IDirect3DSurface9 **outSurface);
+ gl::Error getSurfaceLevel(GLenum target,
+ int level,
+ bool dirty,
+ IDirect3DSurface9 **outSurface) override;
virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT);
virtual gl::Error getBaseTexture(IDirect3DBaseTexture9 **outTexture);
virtual gl::Error generateMipmap(const gl::ImageIndex &sourceIndex, const gl::ImageIndex &destIndex);
@@ -78,7 +83,27 @@ class TextureStorage9_2D : public TextureStorage9
private:
IDirect3DTexture9 *mTexture;
- RenderTarget9 *mRenderTarget;
+ std::vector<RenderTarget9 *> mRenderTargets;
+};
+
+class TextureStorage9_EGLImage final : public TextureStorage9
+{
+ public:
+ TextureStorage9_EGLImage(Renderer9 *renderer, EGLImageD3D *image);
+ ~TextureStorage9_EGLImage() override;
+
+ gl::Error getSurfaceLevel(GLenum target,
+ int level,
+ bool dirty,
+ IDirect3DSurface9 **outSurface) override;
+ gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT) override;
+ gl::Error getBaseTexture(IDirect3DBaseTexture9 **outTexture) override;
+ gl::Error generateMipmap(const gl::ImageIndex &sourceIndex,
+ const gl::ImageIndex &destIndex) override;
+ gl::Error copyToStorage(TextureStorage *destStorage) override;
+
+ private:
+ EGLImageD3D *mImage;
};
class TextureStorage9_Cube : public TextureStorage9
@@ -87,9 +112,10 @@ class TextureStorage9_Cube : public TextureStorage9
TextureStorage9_Cube(Renderer9 *renderer, GLenum internalformat, bool renderTarget, int size, int levels, bool hintLevelZeroOnly);
virtual ~TextureStorage9_Cube();
- static TextureStorage9_Cube *makeTextureStorage9_Cube(TextureStorage *storage);
-
- gl::Error getCubeMapSurface(GLenum faceTarget, int level, bool dirty, IDirect3DSurface9 **outSurface);
+ gl::Error getSurfaceLevel(GLenum target,
+ int level,
+ bool dirty,
+ IDirect3DSurface9 **outSurface) override;
virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT);
virtual gl::Error getBaseTexture(IDirect3DBaseTexture9 **outTexture);
virtual gl::Error generateMipmap(const gl::ImageIndex &sourceIndex, const gl::ImageIndex &destIndex);
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexArray9.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexArray9.h
index fb626bc0cf..992201737f 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexArray9.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexArray9.h
@@ -19,21 +19,12 @@ class Renderer9;
class VertexArray9 : public VertexArrayImpl
{
public:
- VertexArray9(Renderer9 *renderer)
- : VertexArrayImpl(),
- mRenderer(renderer)
+ VertexArray9(const gl::VertexArray::Data &data)
+ : VertexArrayImpl(data)
{
}
virtual ~VertexArray9() { }
-
- virtual void setElementArrayBuffer(const gl::Buffer *buffer) { }
- virtual void setAttribute(size_t idx, const gl::VertexAttribute &attr) { }
- virtual void setAttributeDivisor(size_t idx, GLuint divisor) { }
- virtual void enableAttribute(size_t idx, bool enabledState) { }
-
- private:
- Renderer9 *mRenderer;
};
}
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexBuffer9.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexBuffer9.cpp
index cb5003997f..bfdf137126 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexBuffer9.cpp
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexBuffer9.cpp
@@ -56,24 +56,21 @@ gl::Error VertexBuffer9::initialize(unsigned int size, bool dynamicUsage)
return gl::Error(GL_NO_ERROR);
}
-VertexBuffer9 *VertexBuffer9::makeVertexBuffer9(VertexBuffer *vertexBuffer)
-{
- ASSERT(HAS_DYNAMIC_TYPE(VertexBuffer9*, vertexBuffer));
- return static_cast<VertexBuffer9*>(vertexBuffer);
-}
-
-gl::Error VertexBuffer9::storeVertexAttributes(const gl::VertexAttribute &attrib, const gl::VertexAttribCurrentValueData &currentValue,
- GLint start, GLsizei count, GLsizei instances, unsigned int offset)
+gl::Error VertexBuffer9::storeVertexAttributes(const gl::VertexAttribute &attrib,
+ GLenum currentValueType,
+ GLint start,
+ GLsizei count,
+ GLsizei instances,
+ unsigned int offset,
+ const uint8_t *sourceData)
{
if (!mVertexBuffer)
{
return gl::Error(GL_OUT_OF_MEMORY, "Internal vertex buffer is not initialized.");
}
- gl::Buffer *buffer = attrib.buffer.get();
-
- int inputStride = gl::ComputeVertexAttributeStride(attrib);
- int elementSize = gl::ComputeVertexAttributeTypeSize(attrib);
+ int inputStride = static_cast<int>(gl::ComputeVertexAttributeStride(attrib));
+ int elementSize = static_cast<int>(gl::ComputeVertexAttributeTypeSize(attrib));
DWORD lockFlags = mDynamicUsage ? D3DLOCK_NOOVERWRITE : 0;
@@ -92,37 +89,15 @@ gl::Error VertexBuffer9::storeVertexAttributes(const gl::VertexAttribute &attrib
return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock internal vertex buffer, HRESULT: 0x%08x.", result);
}
- const uint8_t *input = NULL;
- if (attrib.enabled)
- {
- if (buffer)
- {
- BufferD3D *storage = GetImplAs<BufferD3D>(buffer);
- ASSERT(storage);
- error = storage->getData(&input);
- if (error.isError())
- {
- return error;
- }
- input += static_cast<int>(attrib.offset);
- }
- else
- {
- input = static_cast<const uint8_t*>(attrib.pointer);
- }
- }
- else
- {
- input = reinterpret_cast<const uint8_t*>(currentValue.FloatValues);
- }
+ const uint8_t *input = sourceData;
if (instances == 0 || attrib.divisor == 0)
{
input += inputStride * start;
}
- gl::VertexFormat vertexFormat(attrib, currentValue.Type);
- const d3d9::VertexFormat &d3dVertexInfo = d3d9::GetVertexFormatInfo(mRenderer->getCapsDeclTypes(), vertexFormat);
+ gl::VertexFormatType vertexFormatType = gl::GetVertexFormatType(attrib, currentValueType);
+ const d3d9::VertexFormat &d3dVertexInfo = d3d9::GetVertexFormatInfo(mRenderer->getCapsDeclTypes(), vertexFormatType);
bool needsConversion = (d3dVertexInfo.conversionType & VERTEX_CONVERT_CPU) > 0;
if (!needsConversion && inputStride == elementSize)
@@ -196,15 +171,15 @@ IDirect3DVertexBuffer9 * VertexBuffer9::getBuffer() const
gl::Error VertexBuffer9::spaceRequired(const gl::VertexAttribute &attrib, std::size_t count, GLsizei instances,
unsigned int *outSpaceRequired) const
{
- gl::VertexFormat vertexFormat(attrib, GL_FLOAT);
- const d3d9::VertexFormat &d3d9VertexInfo = d3d9::GetVertexFormatInfo(mRenderer->getCapsDeclTypes(), vertexFormat);
+ gl::VertexFormatType vertexFormatType = gl::GetVertexFormatType(attrib, GL_FLOAT);
+ const d3d9::VertexFormat &d3d9VertexInfo = d3d9::GetVertexFormatInfo(mRenderer->getCapsDeclTypes(), vertexFormatType);
if (attrib.enabled)
{
unsigned int elementCount = 0;
if (instances == 0 || attrib.divisor == 0)
{
- elementCount = count;
+ elementCount = static_cast<unsigned int>(count);
}
else
{
@@ -216,7 +191,8 @@ gl::Error VertexBuffer9::spaceRequired(const gl::VertexAttribute &attrib, std::s
{
if (outSpaceRequired)
{
- *outSpaceRequired = d3d9VertexInfo.outputElementSize * elementCount;
+ *outSpaceRequired =
+ static_cast<unsigned int>(d3d9VertexInfo.outputElementSize) * elementCount;
}
return gl::Error(GL_NO_ERROR);
}
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexBuffer9.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexBuffer9.h
index f5b110b22b..64271cbe2a 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexBuffer9.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexBuffer9.h
@@ -23,10 +23,13 @@ class VertexBuffer9 : public VertexBuffer
virtual gl::Error initialize(unsigned int size, bool dynamicUsage);
- static VertexBuffer9 *makeVertexBuffer9(VertexBuffer *vertexBuffer);
-
- virtual gl::Error storeVertexAttributes(const gl::VertexAttribute &attrib, const gl::VertexAttribCurrentValueData &currentValue,
- GLint start, GLsizei count, GLsizei instances, unsigned int offset);
+ gl::Error storeVertexAttributes(const gl::VertexAttribute &attrib,
+ GLenum currentValueType,
+ GLint start,
+ GLsizei count,
+ GLsizei instances,
+ unsigned int offset,
+ const uint8_t *sourceData) override;
virtual gl::Error getSpaceRequired(const gl::VertexAttribute &attrib, GLsizei count, GLsizei instances, unsigned int *outSpaceRequired) const;
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexDeclarationCache.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexDeclarationCache.cpp
index f9eded9b50..a23ab4a290 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexDeclarationCache.cpp
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexDeclarationCache.cpp
@@ -7,10 +7,12 @@
// VertexDeclarationCache.cpp: Implements a helper class to construct and cache vertex declarations.
#include "libANGLE/renderer/d3d/d3d9/VertexDeclarationCache.h"
+
+#include "libANGLE/VertexAttribute.h"
+#include "libANGLE/formatutils.h"
+#include "libANGLE/renderer/d3d/ProgramD3D.h"
#include "libANGLE/renderer/d3d/d3d9/VertexBuffer9.h"
#include "libANGLE/renderer/d3d/d3d9/formatutils9.h"
-#include "libANGLE/Program.h"
-#include "libANGLE/VertexAttribute.h"
namespace rx
{
@@ -40,16 +42,23 @@ VertexDeclarationCache::~VertexDeclarationCache()
}
}
-gl::Error VertexDeclarationCache::applyDeclaration(IDirect3DDevice9 *device, TranslatedAttribute attributes[], gl::Program *program, GLsizei instances, GLsizei *repeatDraw)
+gl::Error VertexDeclarationCache::applyDeclaration(IDirect3DDevice9 *device,
+ const std::vector<TranslatedAttribute> &attributes,
+ gl::Program *program,
+ GLsizei instances,
+ GLsizei *repeatDraw)
{
+ ASSERT(gl::MAX_VERTEX_ATTRIBS >= attributes.size());
+
*repeatDraw = 1;
- int indexedAttribute = gl::MAX_VERTEX_ATTRIBS;
- int instancedAttribute = gl::MAX_VERTEX_ATTRIBS;
+ const size_t invalidAttribIndex = attributes.size();
+ size_t indexedAttribute = invalidAttribIndex;
+ size_t instancedAttribute = invalidAttribIndex;
if (instances == 0)
{
- for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; ++i)
+ for (size_t i = 0; i < attributes.size(); ++i)
{
if (attributes[i].divisor != 0)
{
@@ -64,26 +73,26 @@ gl::Error VertexDeclarationCache::applyDeclaration(IDirect3DDevice9 *device, Tra
if (instances > 0)
{
// Find an indexed attribute to be mapped to D3D stream 0
- for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
+ for (size_t i = 0; i < attributes.size(); i++)
{
if (attributes[i].active)
{
- if (indexedAttribute == gl::MAX_VERTEX_ATTRIBS && attributes[i].divisor == 0)
+ if (indexedAttribute == invalidAttribIndex && attributes[i].divisor == 0)
{
indexedAttribute = i;
}
- else if (instancedAttribute == gl::MAX_VERTEX_ATTRIBS && attributes[i].divisor != 0)
+ else if (instancedAttribute == invalidAttribIndex && attributes[i].divisor != 0)
{
instancedAttribute = i;
}
- if (indexedAttribute != gl::MAX_VERTEX_ATTRIBS && instancedAttribute != gl::MAX_VERTEX_ATTRIBS)
+ if (indexedAttribute != invalidAttribIndex && instancedAttribute != invalidAttribIndex)
break; // Found both an indexed and instanced attribute
}
}
// The validation layer checks that there is at least one active attribute with a zero divisor as per
// the GL_ANGLE_instanced_arrays spec.
- ASSERT(indexedAttribute != gl::MAX_VERTEX_ATTRIBS);
+ ASSERT(indexedAttribute != invalidAttribIndex);
}
D3DCAPS9 caps;
@@ -92,19 +101,22 @@ gl::Error VertexDeclarationCache::applyDeclaration(IDirect3DDevice9 *device, Tra
D3DVERTEXELEMENT9 elements[gl::MAX_VERTEX_ATTRIBS + 1];
D3DVERTEXELEMENT9 *element = &elements[0];
- for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
+ ProgramD3D *programD3D = GetImplAs<ProgramD3D>(program);
+ const auto &semanticIndexes = programD3D->getSemanticIndexes();
+
+ for (size_t i = 0; i < attributes.size(); i++)
{
if (attributes[i].active)
{
// Directly binding the storage buffer is not supported for d3d9
ASSERT(attributes[i].storage == NULL);
- int stream = i;
+ int stream = static_cast<int>(i);
if (instances > 0)
{
// Due to a bug on ATI cards we can't enable instancing when none of the attributes are instanced.
- if (instancedAttribute == gl::MAX_VERTEX_ATTRIBS)
+ if (instancedAttribute == invalidAttribIndex)
{
*repeatDraw = instances;
}
@@ -116,7 +128,7 @@ gl::Error VertexDeclarationCache::applyDeclaration(IDirect3DDevice9 *device, Tra
}
else if (i == 0)
{
- stream = indexedAttribute;
+ stream = static_cast<int>(indexedAttribute);
}
UINT frequency = 1;
@@ -135,7 +147,7 @@ gl::Error VertexDeclarationCache::applyDeclaration(IDirect3DDevice9 *device, Tra
}
}
- VertexBuffer9 *vertexBuffer = VertexBuffer9::makeVertexBuffer9(attributes[i].vertexBuffer);
+ VertexBuffer9 *vertexBuffer = GetAs<VertexBuffer9>(attributes[i].vertexBuffer);
if (mAppliedVBs[stream].serial != attributes[i].serial ||
mAppliedVBs[stream].stride != attributes[i].stride ||
@@ -147,20 +159,20 @@ gl::Error VertexDeclarationCache::applyDeclaration(IDirect3DDevice9 *device, Tra
mAppliedVBs[stream].offset = attributes[i].offset;
}
- gl::VertexFormat vertexFormat(*attributes[i].attribute, GL_FLOAT);
- const d3d9::VertexFormat &d3d9VertexInfo = d3d9::GetVertexFormatInfo(caps.DeclTypes, vertexFormat);
+ gl::VertexFormatType vertexformatType = gl::GetVertexFormatType(*attributes[i].attribute, GL_FLOAT);
+ const d3d9::VertexFormat &d3d9VertexInfo = d3d9::GetVertexFormatInfo(caps.DeclTypes, vertexformatType);
- element->Stream = stream;
+ element->Stream = static_cast<WORD>(stream);
element->Offset = 0;
- element->Type = d3d9VertexInfo.nativeFormat;
+ element->Type = static_cast<BYTE>(d3d9VertexInfo.nativeFormat);
element->Method = D3DDECLMETHOD_DEFAULT;
element->Usage = D3DDECLUSAGE_TEXCOORD;
- element->UsageIndex = program->getSemanticIndex(i);
+ element->UsageIndex = static_cast<BYTE>(semanticIndexes[i]);
element++;
}
}
- if (instances == 0 || instancedAttribute == gl::MAX_VERTEX_ATTRIBS)
+ if (instances == 0 || instancedAttribute == invalidAttribIndex)
{
if (mInstancingEnabled)
{
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexDeclarationCache.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexDeclarationCache.h
index fbd673097f..bad4de4d6b 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexDeclarationCache.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexDeclarationCache.h
@@ -27,7 +27,11 @@ class VertexDeclarationCache
VertexDeclarationCache();
~VertexDeclarationCache();
- gl::Error applyDeclaration(IDirect3DDevice9 *device, TranslatedAttribute attributes[], gl::Program *program, GLsizei instances, GLsizei *repeatDraw);
+ gl::Error applyDeclaration(IDirect3DDevice9 *device,
+ const std::vector<TranslatedAttribute> &attributes,
+ gl::Program *program,
+ GLsizei instances,
+ GLsizei *repeatDraw);
void markStateDirty();
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/formatutils9.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/formatutils9.cpp
index 9bad5503d9..b672a60e3c 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/formatutils9.cpp
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/formatutils9.cpp
@@ -119,8 +119,8 @@ static D3D9FormatInfoMap BuildD3D9FormatInfoMap()
InsertD3DFormatInfo(&map, D3DFMT_L8, 8, 1, 1, 0, 0, 0, 0, 8, 0, 0, GL_LUMINANCE8_EXT, GenerateMip<L8>, ReadColor<L8, GLfloat> );
InsertD3DFormatInfo(&map, D3DFMT_A8, 8, 1, 1, 0, 0, 0, 8, 0, 0, 0, GL_ALPHA8_EXT, GenerateMip<A8>, ReadColor<A8, GLfloat> );
InsertD3DFormatInfo(&map, D3DFMT_A8L8, 16, 1, 1, 0, 0, 0, 8, 8, 0, 0, GL_LUMINANCE8_ALPHA8_EXT, GenerateMip<A8L8>, ReadColor<A8L8, GLfloat> );
- InsertD3DFormatInfo(&map, D3DFMT_A4R4G4B4, 16, 1, 1, 4, 4, 4, 4, 0, 0, 0, GL_BGRA4_ANGLEX, GenerateMip<B4G4R4A4>, ReadColor<B4G4R4A4, GLfloat> );
- InsertD3DFormatInfo(&map, D3DFMT_A1R5G5B5, 16, 1, 1, 5, 5, 5, 1, 0, 0, 0, GL_BGR5_A1_ANGLEX, GenerateMip<B5G5R5A1>, ReadColor<B5G5R5A1, GLfloat> );
+ InsertD3DFormatInfo(&map, D3DFMT_A4R4G4B4, 16, 1, 1, 4, 4, 4, 4, 0, 0, 0, GL_BGRA4_ANGLEX, GenerateMip<A4R4G4B4>, ReadColor<A4R4G4B4, GLfloat> );
+ InsertD3DFormatInfo(&map, D3DFMT_A1R5G5B5, 16, 1, 1, 5, 5, 5, 1, 0, 0, 0, GL_BGR5_A1_ANGLEX, GenerateMip<A1R5G5B5>, ReadColor<A1R5G5B5, GLfloat> );
InsertD3DFormatInfo(&map, D3DFMT_R5G6B5, 16, 1, 1, 5, 6, 5, 0, 0, 0, 0, GL_RGB565, GenerateMip<R5G6B5>, ReadColor<R5G6B5, GLfloat> );
InsertD3DFormatInfo(&map, D3DFMT_X8R8G8B8, 32, 1, 1, 8, 8, 8, 0, 0, 0, 0, GL_BGRA8_EXT, GenerateMip<B8G8R8X8>, ReadColor<B8G8R8X8, GLfloat> );
InsertD3DFormatInfo(&map, D3DFMT_A8R8G8B8, 32, 1, 1, 8, 8, 8, 8, 0, 0, 0, GL_BGRA8_EXT, GenerateMip<B8G8R8A8>, ReadColor<B8G8R8A8, GLfloat> );
@@ -475,16 +475,25 @@ template <class T> struct UseFallback { enum { type = T::fallback }; };
// and the D3DDECLTYPE member needed for the vertex declaration in declflag.
template <GLenum fromType, bool normalized, int size, template <class T> class PreferenceRule>
struct Converter
- : VertexDataConverter<typename GLToCType<fromType>::type,
- WidenRule<PreferenceRule< VertexTypeMapping<fromType, normalized> >::type, size>,
- ConversionRule<fromType,
- normalized,
- PreferenceRule< VertexTypeMapping<fromType, normalized> >::type>,
- DefaultVertexValues<typename D3DToCType<PreferenceRule< VertexTypeMapping<fromType, normalized> >::type>::type, normalized > >
+ : VertexDataConverter<
+ typename GLToCType<fromType>::type,
+ WidenRule<PreferenceRule<VertexTypeMapping<fromType, normalized>>::type, size>,
+ ConversionRule<fromType,
+ normalized,
+ PreferenceRule<VertexTypeMapping<fromType, normalized>>::type>,
+ DefaultVertexValues<typename D3DToCType<PreferenceRule<
+ VertexTypeMapping<fromType, normalized>>::type>::type,
+ normalized>>
{
private:
- enum { d3dtype = PreferenceRule< VertexTypeMapping<fromType, normalized> >::type };
- enum { d3dsize = WidenRule<d3dtype, size>::finalWidth };
+ enum
+ {
+ d3dtype = PreferenceRule<VertexTypeMapping<fromType, normalized>>::type
+ };
+ enum
+ {
+ d3dsize = WidenRule<d3dtype, size>::finalWidth
+ };
public:
enum { capflag = VertexTypeFlags<d3dtype, d3dsize>::capflag };
@@ -555,12 +564,12 @@ static inline unsigned int ComputeTypeIndex(GLenum type)
}
}
-const VertexFormat &GetVertexFormatInfo(DWORD supportedDeclTypes, const gl::VertexFormat &vertexFormat)
+const VertexFormat &GetVertexFormatInfo(DWORD supportedDeclTypes, gl::VertexFormatType vertexFormatType)
{
static bool initialized = false;
- static DWORD intializedDeclTypes = 0;
+ static DWORD initializedDeclTypes = 0;
static VertexFormat formatConverters[NUM_GL_VERTEX_ATTRIB_TYPES][2][4];
- if (intializedDeclTypes != supportedDeclTypes)
+ if (initializedDeclTypes != supportedDeclTypes)
{
const TranslationDescription translations[NUM_GL_VERTEX_ATTRIB_TYPES][2][4] = // [GL types as enumerated by typeIndex()][normalized][size-1]
{
@@ -589,12 +598,14 @@ const VertexFormat &GetVertexFormatInfo(DWORD supportedDeclTypes, const gl::Vert
}
}
initialized = true;
- intializedDeclTypes = supportedDeclTypes;
+ initializedDeclTypes = supportedDeclTypes;
}
+ const gl::VertexFormat &vertexFormat = gl::GetVertexFormatFromType(vertexFormatType);
+
// Pure integer attributes only supported in ES3.0
- ASSERT(!vertexFormat.mPureInteger);
- return formatConverters[ComputeTypeIndex(vertexFormat.mType)][vertexFormat.mNormalized][vertexFormat.mComponents - 1];
+ ASSERT(!vertexFormat.pureInteger);
+ return formatConverters[ComputeTypeIndex(vertexFormat.type)][vertexFormat.normalized][vertexFormat.components - 1];
}
}
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/formatutils9.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/formatutils9.h
index 15e26599c8..c55010760d 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/formatutils9.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/formatutils9.h
@@ -10,12 +10,12 @@
#ifndef LIBANGLE_RENDERER_D3D_D3D9_FORMATUTILS9_H_
#define LIBANGLE_RENDERER_D3D_D3D9_FORMATUTILS9_H_
-#include "libANGLE/renderer/d3d/formatutilsD3D.h"
-#include "libANGLE/angletypes.h"
+#include <map>
#include "common/platform.h"
-
-#include <map>
+#include "libANGLE/angletypes.h"
+#include "libANGLE/formatutils.h"
+#include "libANGLE/renderer/d3d/formatutilsD3D.h"
namespace rx
{
@@ -64,7 +64,7 @@ struct VertexFormat
D3DDECLTYPE nativeFormat;
GLenum componentType;
};
-const VertexFormat &GetVertexFormatInfo(DWORD supportedDeclTypes, const gl::VertexFormat &vertexFormat);
+const VertexFormat &GetVertexFormatInfo(DWORD supportedDeclTypes, gl::VertexFormatType vertexFormatType);
struct TextureFormat
{
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/renderer9_utils.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/renderer9_utils.cpp
index c9711ac052..8622dc4d13 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/renderer9_utils.cpp
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/renderer9_utils.cpp
@@ -8,16 +8,17 @@
// specific to the D3D9 renderer.
#include "libANGLE/renderer/d3d/d3d9/renderer9_utils.h"
-#include "libANGLE/renderer/d3d/d3d9/formatutils9.h"
-#include "libANGLE/renderer/d3d/FramebufferD3D.h"
-#include "libANGLE/renderer/Workarounds.h"
-#include "libANGLE/formatutils.h"
-#include "libANGLE/Framebuffer.h"
-#include "libANGLE/renderer/d3d/d3d9/RenderTarget9.h"
#include "common/mathutil.h"
#include "common/debug.h"
+#include "libANGLE/formatutils.h"
+#include "libANGLE/Framebuffer.h"
+#include "libANGLE/renderer/d3d/d3d9/formatutils9.h"
+#include "libANGLE/renderer/d3d/d3d9/RenderTarget9.h"
+#include "libANGLE/renderer/d3d/FramebufferD3D.h"
+#include "libANGLE/renderer/d3d/WorkaroundsD3D.h"
+
#include "third_party/systeminfo/SystemInfo.h"
namespace rx
@@ -208,7 +209,8 @@ D3DTEXTUREFILTERTYPE ConvertMagFilter(GLenum magFilter, float maxAnisotropy)
return d3dMagFilter;
}
-void ConvertMinFilter(GLenum minFilter, D3DTEXTUREFILTERTYPE *d3dMinFilter, D3DTEXTUREFILTERTYPE *d3dMipFilter, float maxAnisotropy)
+void ConvertMinFilter(GLenum minFilter, D3DTEXTUREFILTERTYPE *d3dMinFilter, D3DTEXTUREFILTERTYPE *d3dMipFilter,
+ float *d3dLodBias, float maxAnisotropy, size_t baseLevel)
{
switch (minFilter)
{
@@ -242,6 +244,20 @@ void ConvertMinFilter(GLenum minFilter, D3DTEXTUREFILTERTYPE *d3dMinFilter, D3DT
UNREACHABLE();
}
+ // Disabling mipmapping will always sample from level 0 of the texture. It is possible to work
+ // around this by modifying D3DSAMP_MAXMIPLEVEL to force a specific mip level to become the
+ // lowest sampled mip level and using a large negative value for D3DSAMP_MIPMAPLODBIAS to
+ // ensure that only the base mip level is sampled.
+ if (baseLevel > 0 && *d3dMipFilter == D3DTEXF_NONE)
+ {
+ *d3dMipFilter = D3DTEXF_POINT;
+ *d3dLodBias = -static_cast<float>(gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
+ }
+ else
+ {
+ *d3dLodBias = 0.0f;
+ }
+
if (maxAnisotropy > 1.0f)
{
*d3dMinFilter = D3DTEXF_ANISOTROPIC;
@@ -258,6 +274,16 @@ D3DMULTISAMPLE_TYPE GetMultisampleType(GLuint samples)
namespace d3d9_gl
{
+unsigned int GetReservedVertexUniformVectors()
+{
+ return 3; // dx_ViewCoords, dx_ViewAdjust and dx_DepthRange.
+}
+
+unsigned int GetReservedFragmentUniformVectors()
+{
+ return 3; // dx_ViewCoords, dx_DepthFront and dx_DepthRange.
+}
+
GLsizei GetSamplesCount(D3DMULTISAMPLE_TYPE type)
{
return (type != D3DMULTISAMPLE_NONMASKABLE) ? type : 0;
@@ -303,7 +329,7 @@ static gl::TextureCaps GenerateTextureFormatCaps(GLenum internalFormat, IDirect3
}
textureCaps.sampleCounts.insert(1);
- for (size_t i = D3DMULTISAMPLE_2_SAMPLES; i <= D3DMULTISAMPLE_16_SAMPLES; i++)
+ for (unsigned int i = D3DMULTISAMPLE_2_SAMPLES; i <= D3DMULTISAMPLE_16_SAMPLES; i++)
{
D3DMULTISAMPLE_TYPE multisampleType = D3DMULTISAMPLE_TYPE(i);
@@ -318,8 +344,14 @@ static gl::TextureCaps GenerateTextureFormatCaps(GLenum internalFormat, IDirect3
return textureCaps;
}
-void GenerateCaps(IDirect3D9 *d3d9, IDirect3DDevice9 *device, D3DDEVTYPE deviceType, UINT adapter, gl::Caps *caps,
- gl::TextureCapsMap *textureCapsMap, gl::Extensions *extensions)
+void GenerateCaps(IDirect3D9 *d3d9,
+ IDirect3DDevice9 *device,
+ D3DDEVTYPE deviceType,
+ UINT adapter,
+ gl::Caps *caps,
+ gl::TextureCapsMap *textureCapsMap,
+ gl::Extensions *extensions,
+ gl::Limitations *limitations)
{
D3DCAPS9 deviceCaps;
if (FAILED(d3d9->GetDeviceCaps(adapter, deviceType, &deviceCaps)))
@@ -413,9 +445,9 @@ void GenerateCaps(IDirect3D9 *d3d9, IDirect3DDevice9 *device, D3DDEVTYPE deviceT
// Vertex shader limits
caps->maxVertexAttributes = 16;
- const size_t reservedVertexUniformVectors = 2; // dx_ViewAdjust and dx_DepthRange.
const size_t MAX_VERTEX_CONSTANT_VECTORS_D3D9 = 256;
- caps->maxVertexUniformVectors = MAX_VERTEX_CONSTANT_VECTORS_D3D9 - reservedVertexUniformVectors;
+ caps->maxVertexUniformVectors =
+ MAX_VERTEX_CONSTANT_VECTORS_D3D9 - GetReservedVertexUniformVectors();
caps->maxVertexUniformComponents = caps->maxVertexUniformVectors * 4;
caps->maxVertexUniformBlocks = 0;
@@ -441,12 +473,12 @@ void GenerateCaps(IDirect3D9 *d3d9, IDirect3DDevice9 *device, D3DDEVTYPE deviceT
}
// Fragment shader limits
- const size_t reservedPixelUniformVectors = 3; // dx_ViewCoords, dx_DepthFront and dx_DepthRange.
-
const size_t MAX_PIXEL_CONSTANT_VECTORS_SM3 = 224;
const size_t MAX_PIXEL_CONSTANT_VECTORS_SM2 = 32;
- caps->maxFragmentUniformVectors = ((deviceCaps.PixelShaderVersion >= D3DPS_VERSION(3, 0)) ? MAX_PIXEL_CONSTANT_VECTORS_SM3
- : MAX_PIXEL_CONSTANT_VECTORS_SM2) - reservedPixelUniformVectors;
+ caps->maxFragmentUniformVectors =
+ ((deviceCaps.PixelShaderVersion >= D3DPS_VERSION(3, 0)) ? MAX_PIXEL_CONSTANT_VECTORS_SM3
+ : MAX_PIXEL_CONSTANT_VECTORS_SM2) -
+ GetReservedFragmentUniformVectors();
caps->maxFragmentUniformComponents = caps->maxFragmentUniformVectors * 4;
caps->maxFragmentUniformBlocks = 0;
caps->maxFragmentInputComponents = caps->maxVertexOutputComponents;
@@ -472,10 +504,12 @@ void GenerateCaps(IDirect3D9 *d3d9, IDirect3DDevice9 *device, D3DDEVTYPE deviceT
caps->maxTransformFeedbackSeparateAttributes = 0;
caps->maxTransformFeedbackSeparateComponents = 0;
+ // Multisample limits
+ caps->maxSamples = maxSamples;
+
// GL extension support
extensions->setTextureExtensionSupport(*textureCapsMap);
extensions->elementIndexUint = deviceCaps.MaxVertexIndex >= (1 << 16);
- extensions->packedDepthStencil = true;
extensions->getProgramBinary = true;
extensions->rgb8rgba8 = true;
extensions->readFormatBGRA = true;
@@ -486,7 +520,7 @@ void GenerateCaps(IDirect3D9 *d3d9, IDirect3DDevice9 *device, D3DDEVTYPE deviceT
// textureRG is emulated and not performant.
extensions->textureRG = false;
- D3DADAPTER_IDENTIFIER9 adapterId = { 0 };
+ D3DADAPTER_IDENTIFIER9 adapterId = {};
if (SUCCEEDED(d3d9->GetAdapterIdentifier(adapter, 0, &adapterId)))
{
// ATI cards on XP have problems with non-power-of-two textures.
@@ -524,11 +558,11 @@ void GenerateCaps(IDirect3D9 *d3d9, IDirect3DDevice9 *device, D3DDEVTYPE deviceT
SafeRelease(eventQuery);
extensions->timerQuery = false; // Unimplemented
+ extensions->disjointTimerQuery = false;
extensions->robustness = true;
extensions->blendMinMax = true;
extensions->framebufferBlit = true;
extensions->framebufferMultisample = true;
- extensions->maxSamples = maxSamples;
extensions->instancedArrays = deviceCaps.PixelShaderVersion >= D3DPS_VERSION(3, 0);
extensions->packReverseRowOrder = true;
extensions->standardDerivatives = (deviceCaps.PS20Caps.Caps & D3DPS20CAPS_GRADIENTINSTRUCTIONS) != 0;
@@ -536,7 +570,27 @@ void GenerateCaps(IDirect3D9 *d3d9, IDirect3DDevice9 *device, D3DDEVTYPE deviceT
extensions->fragDepth = true;
extensions->textureUsage = true;
extensions->translatedShaderSource = true;
+ extensions->fboRenderMipmap = false;
+ extensions->discardFramebuffer = false; // It would be valid to set this to true, since glDiscardFramebufferEXT is just a hint
extensions->colorBufferFloat = false;
+ extensions->debugMarker = true;
+ extensions->eglImage = true;
+ extensions->unpackSubimage = true;
+ extensions->packSubimage = true;
+ extensions->vertexArrayObject = true;
+ extensions->noError = true;
+
+ // D3D9 has no concept of separate masks and refs for front and back faces in the depth stencil
+ // state.
+ limitations->noSeparateStencilRefsAndMasks = true;
+
+ // D3D9 shader models have limited support for looping, so the Appendix A
+ // index/loop limitations are necessary. Workarounds that are needed to
+ // support dynamic indexing of vectors on HLSL also don't work on D3D9.
+ limitations->shadersRequireIndexedLoopValidation = true;
+
+ // D3D9 cannot support constant color and alpha blend funcs together
+ limitations->noSimultaneousConstantColorAndAlphaBlendFunc = true;
}
}
@@ -571,21 +625,9 @@ void MakeValidSize(bool isImage, D3DFORMAT format, GLsizei *requestWidth, GLsize
*levelOffset = upsampleCount;
}
-gl::Error GetAttachmentRenderTarget(const gl::FramebufferAttachment *attachment, RenderTarget9 **outRT)
-{
- RenderTargetD3D *renderTarget = NULL;
- gl::Error error = rx::GetAttachmentRenderTarget(attachment, &renderTarget);
- if (error.isError())
- {
- return error;
- }
- *outRT = RenderTarget9::makeRenderTarget9(renderTarget);
- return gl::Error(GL_NO_ERROR);
-}
-
-Workarounds GenerateWorkarounds()
+WorkaroundsD3D GenerateWorkarounds()
{
- Workarounds workarounds;
+ WorkaroundsD3D workarounds;
workarounds.mrtPerfWorkaround = true;
workarounds.setDataFasterThanImageUpload = false;
workarounds.useInstancedPointSpriteEmulation = false;
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/renderer9_utils.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/renderer9_utils.h
index 3c6a57aee3..aa494adb62 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/renderer9_utils.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/renderer9_utils.h
@@ -22,7 +22,7 @@ class FramebufferAttachment;
namespace rx
{
class RenderTarget9;
-struct Workarounds;
+struct WorkaroundsD3D;
namespace gl_d3d9
{
@@ -37,7 +37,8 @@ D3DCULL ConvertCullMode(GLenum cullFace, GLenum frontFace);
D3DCUBEMAP_FACES ConvertCubeFace(GLenum cubeFace);
DWORD ConvertColorMask(bool red, bool green, bool blue, bool alpha);
D3DTEXTUREFILTERTYPE ConvertMagFilter(GLenum magFilter, float maxAnisotropy);
-void ConvertMinFilter(GLenum minFilter, D3DTEXTUREFILTERTYPE *d3dMinFilter, D3DTEXTUREFILTERTYPE *d3dMipFilter, float maxAnisotropy);
+void ConvertMinFilter(GLenum minFilter, D3DTEXTUREFILTERTYPE *d3dMinFilter, D3DTEXTUREFILTERTYPE *d3dMipFilter,
+ float *d3dLodBias, float maxAnisotropy, size_t baseLevel);
D3DMULTISAMPLE_TYPE GetMultisampleType(GLuint samples);
@@ -46,13 +47,22 @@ D3DMULTISAMPLE_TYPE GetMultisampleType(GLuint samples);
namespace d3d9_gl
{
+unsigned int GetReservedVertexUniformVectors();
+
+unsigned int GetReservedFragmentUniformVectors();
+
GLsizei GetSamplesCount(D3DMULTISAMPLE_TYPE type);
bool IsFormatChannelEquivalent(D3DFORMAT d3dformat, GLenum format);
-void GenerateCaps(IDirect3D9 *d3d9, IDirect3DDevice9 *device, D3DDEVTYPE deviceType, UINT adapter, gl::Caps *caps,
- gl::TextureCapsMap *textureCapsMap, gl::Extensions *extensions);
-
+void GenerateCaps(IDirect3D9 *d3d9,
+ IDirect3DDevice9 *device,
+ D3DDEVTYPE deviceType,
+ UINT adapter,
+ gl::Caps *caps,
+ gl::TextureCapsMap *textureCapsMap,
+ gl::Extensions *extensions,
+ gl::Limitations *limitations);
}
namespace d3d9
@@ -76,9 +86,7 @@ inline bool isDeviceLostError(HRESULT errorCode)
}
}
-gl::Error GetAttachmentRenderTarget(const gl::FramebufferAttachment *attachment, RenderTarget9 **outRT);
-Workarounds GenerateWorkarounds();
-
+WorkaroundsD3D GenerateWorkarounds();
}
}
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/vertexconversion.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/vertexconversion.h
index 32eb376a78..aa05934bc8 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/vertexconversion.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/vertexconversion.h
@@ -149,7 +149,10 @@ struct NormalizedDefaultValues
// static const std::size_t finalSize: number of bytes per output vertex
// static void convertArray(const void *in, std::size_t stride, std::size_t n, void *out): convert an array of vertices. Input may be strided, but output will be unstrided.
-template <class InT, class WidenRule, class Converter, class DefaultValueRule = SimpleDefaultValues<InT> >
+template <class InT,
+ class WidenRule,
+ class Converter,
+ class DefaultValueRule = SimpleDefaultValues<InT>>
struct VertexDataConverter
{
typedef typename Converter::OutputType OutputType;
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/formatutilsD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/formatutilsD3D.cpp
index 8a4d41cbd9..e1c955eb06 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/formatutilsD3D.cpp
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/formatutilsD3D.cpp
@@ -106,8 +106,8 @@ static FormatWriteFunctionMap BuildFormatWriteFunctionMap()
InsertFormatWriteFunctionMapping(&map, GL_ALPHA, GL_HALF_FLOAT_OES, WriteColor<A16F, GLfloat> );
InsertFormatWriteFunctionMapping(&map, GL_BGRA_EXT, GL_UNSIGNED_BYTE, WriteColor<B8G8R8A8, GLfloat> );
- InsertFormatWriteFunctionMapping(&map, GL_BGRA_EXT, GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT, WriteColor<B4G4R4A4, GLfloat> );
- InsertFormatWriteFunctionMapping(&map, GL_BGRA_EXT, GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT, WriteColor<B5G5R5A1, GLfloat> );
+ InsertFormatWriteFunctionMapping(&map, GL_BGRA_EXT, GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT, WriteColor<A4R4G4B4, GLfloat> );
+ InsertFormatWriteFunctionMapping(&map, GL_BGRA_EXT, GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT, WriteColor<A1R5G5B5, GLfloat> );
InsertFormatWriteFunctionMapping(&map, GL_SRGB_EXT, GL_UNSIGNED_BYTE, WriteColor<R8G8B8, GLfloat> );
InsertFormatWriteFunctionMapping(&map, GL_SRGB_ALPHA_EXT, GL_UNSIGNED_BYTE, WriteColor<R8G8B8A8, GLfloat> );
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/imageformats.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/imageformats.h
index e0f9a16c1a..76f1830e64 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/imageformats.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/imageformats.h
@@ -285,6 +285,8 @@ struct B8G8R8
struct R5G6B5
{
+ // OpenGL ES 2.0.25 spec Section 3.6.2: "Components are packed with the first component in the most significant
+ // bits of the bitfield, and successive component occupying progressively less significant locations"
unsigned short RGB;
static void readColor(gl::ColorF *dst, const R5G6B5 *src)
@@ -491,157 +493,123 @@ struct B8G8R8X8
}
};
-struct B5G5R5A1
+struct A1R5G5B5
{
- unsigned short BGRA;
+ unsigned short ARGB;
- static void readColor(gl::ColorF *dst, const B5G5R5A1 *src)
+ static void readColor(gl::ColorF *dst, const A1R5G5B5 *src)
{
- dst->alpha = gl::normalizedToFloat<1>(gl::getShiftedData<1, 15>(src->BGRA));
- dst->red = gl::normalizedToFloat<5>(gl::getShiftedData<5, 10>(src->BGRA));
- dst->green = gl::normalizedToFloat<5>(gl::getShiftedData<5, 5>(src->BGRA));
- dst->blue = gl::normalizedToFloat<5>(gl::getShiftedData<5, 0>(src->BGRA));
+ dst->alpha = gl::normalizedToFloat<1>(gl::getShiftedData<1, 15>(src->ARGB));
+ dst->red = gl::normalizedToFloat<5>(gl::getShiftedData<5, 10>(src->ARGB));
+ dst->green = gl::normalizedToFloat<5>(gl::getShiftedData<5, 5>(src->ARGB));
+ dst->blue = gl::normalizedToFloat<5>(gl::getShiftedData<5, 0>(src->ARGB));
}
- static void writeColor(B5G5R5A1 *dst, const gl::ColorF *src)
+ static void writeColor(A1R5G5B5 *dst, const gl::ColorF *src)
{
- dst->BGRA = gl::shiftData<1, 15>(gl::floatToNormalized<1, unsigned short>(src->alpha)) |
+ dst->ARGB = gl::shiftData<1, 15>(gl::floatToNormalized<1, unsigned short>(src->alpha)) |
gl::shiftData<5, 10>(gl::floatToNormalized<5, unsigned short>(src->red)) |
gl::shiftData<5, 5>(gl::floatToNormalized<5, unsigned short>(src->green)) |
gl::shiftData<5, 0>(gl::floatToNormalized<5, unsigned short>(src->blue));
}
- static void average(B5G5R5A1 *dst, const B5G5R5A1 *src1, const B5G5R5A1 *src2)
+ static void average(A1R5G5B5 *dst, const A1R5G5B5 *src1, const A1R5G5B5 *src2)
{
- dst->BGRA = gl::shiftData<1, 15>(gl::average(gl::getShiftedData<1, 15>(src1->BGRA), gl::getShiftedData<1, 15>(src2->BGRA))) |
- gl::shiftData<5, 10>(gl::average(gl::getShiftedData<5, 10>(src1->BGRA), gl::getShiftedData<5, 10>(src2->BGRA))) |
- gl::shiftData<5, 5>(gl::average(gl::getShiftedData<5, 5>(src1->BGRA), gl::getShiftedData<5, 5>(src2->BGRA))) |
- gl::shiftData<5, 0>(gl::average(gl::getShiftedData<5, 0>(src1->BGRA), gl::getShiftedData<5, 0>(src2->BGRA)));
+ dst->ARGB = gl::shiftData<1, 15>(gl::average(gl::getShiftedData<1, 15>(src1->ARGB), gl::getShiftedData<1, 15>(src2->ARGB))) |
+ gl::shiftData<5, 10>(gl::average(gl::getShiftedData<5, 10>(src1->ARGB), gl::getShiftedData<5, 10>(src2->ARGB))) |
+ gl::shiftData<5, 5>(gl::average(gl::getShiftedData<5, 5>(src1->ARGB), gl::getShiftedData<5, 5>(src2->ARGB))) |
+ gl::shiftData<5, 0>(gl::average(gl::getShiftedData<5, 0>(src1->ARGB), gl::getShiftedData<5, 0>(src2->ARGB)));
}
};
struct R5G5B5A1
{
+ // OpenGL ES 2.0.25 spec Section 3.6.2: "Components are packed with the first component in the most significant
+ // bits of the bitfield, and successive component occupying progressively less significant locations"
unsigned short RGBA;
static void readColor(gl::ColorF *dst, const R5G5B5A1 *src)
{
- dst->alpha = gl::normalizedToFloat<1>(gl::getShiftedData<1, 15>(src->RGBA));
- dst->blue = gl::normalizedToFloat<5>(gl::getShiftedData<5, 10>(src->RGBA));
- dst->green = gl::normalizedToFloat<5>(gl::getShiftedData<5, 5>(src->RGBA));
- dst->red = gl::normalizedToFloat<5>(gl::getShiftedData<5, 0>(src->RGBA));
+ dst->red = gl::normalizedToFloat<5>(gl::getShiftedData<5, 11>(src->RGBA));
+ dst->green = gl::normalizedToFloat<5>(gl::getShiftedData<5, 6>(src->RGBA));
+ dst->blue = gl::normalizedToFloat<5>(gl::getShiftedData<5, 1>(src->RGBA));
+ dst->alpha = gl::normalizedToFloat<1>(gl::getShiftedData<1, 0>(src->RGBA));
}
static void writeColor(R5G5B5A1 *dst, const gl::ColorF *src)
{
- dst->RGBA = gl::shiftData<1, 15>(gl::floatToNormalized<1, unsigned short>(src->alpha)) |
- gl::shiftData<5, 10>(gl::floatToNormalized<5, unsigned short>(src->blue)) |
- gl::shiftData<5, 5>(gl::floatToNormalized<5, unsigned short>(src->green)) |
- gl::shiftData<5, 0>(gl::floatToNormalized<5, unsigned short>(src->red));
+ dst->RGBA = gl::shiftData<5, 11>(gl::floatToNormalized<5, unsigned short>(src->red)) |
+ gl::shiftData<5, 6>(gl::floatToNormalized<5, unsigned short>(src->green)) |
+ gl::shiftData<5, 1>(gl::floatToNormalized<5, unsigned short>(src->blue)) |
+ gl::shiftData<1, 0>(gl::floatToNormalized<1, unsigned short>(src->alpha));
}
static void average(R5G5B5A1 *dst, const R5G5B5A1 *src1, const R5G5B5A1 *src2)
{
- dst->RGBA = gl::shiftData<1, 15>(gl::average(gl::getShiftedData<1, 15>(src1->RGBA), gl::getShiftedData<1, 15>(src2->RGBA))) |
- gl::shiftData<5, 10>(gl::average(gl::getShiftedData<5, 10>(src1->RGBA), gl::getShiftedData<5, 10>(src2->RGBA))) |
- gl::shiftData<5, 5>(gl::average(gl::getShiftedData<5, 5>(src1->RGBA), gl::getShiftedData<5, 5>(src2->RGBA))) |
- gl::shiftData<5, 0>(gl::average(gl::getShiftedData<5, 0>(src1->RGBA), gl::getShiftedData<5, 0>(src2->RGBA)));
+ dst->RGBA = gl::shiftData<5, 11>(gl::average(gl::getShiftedData<5, 11>(src1->RGBA), gl::getShiftedData<5, 11>(src2->RGBA))) |
+ gl::shiftData<5, 6>(gl::average(gl::getShiftedData<5, 6>(src1->RGBA), gl::getShiftedData<5, 6>(src2->RGBA))) |
+ gl::shiftData<5, 1>(gl::average(gl::getShiftedData<5, 1>(src1->RGBA), gl::getShiftedData<5, 1>(src2->RGBA))) |
+ gl::shiftData<1, 0>(gl::average(gl::getShiftedData<1, 0>(src1->RGBA), gl::getShiftedData<1, 0>(src2->RGBA)));
}
};
struct R4G4B4A4
{
- unsigned char R : 4;
- unsigned char G : 4;
- unsigned char B : 4;
- unsigned char A : 4;
+ // OpenGL ES 2.0.25 spec Section 3.6.2: "Components are packed with the first component in the most significant
+ // bits of the bitfield, and successive component occupying progressively less significant locations"
+ unsigned short RGBA;
static void readColor(gl::ColorF *dst, const R4G4B4A4 *src)
{
- dst->red = gl::normalizedToFloat<4>(src->R);
- dst->green = gl::normalizedToFloat<4>(src->G);
- dst->blue = gl::normalizedToFloat<4>(src->B);
- dst->alpha = gl::normalizedToFloat<4>(src->A);
+ dst->red = gl::normalizedToFloat<4>(gl::getShiftedData<4, 12>(src->RGBA));
+ dst->green = gl::normalizedToFloat<4>(gl::getShiftedData<4, 8>(src->RGBA));
+ dst->blue = gl::normalizedToFloat<4>(gl::getShiftedData<4, 4>(src->RGBA));
+ dst->alpha = gl::normalizedToFloat<4>(gl::getShiftedData<4, 0>(src->RGBA));
}
static void writeColor(R4G4B4A4 *dst, const gl::ColorF *src)
{
- dst->R = gl::floatToNormalized<4, unsigned char>(src->red);
- dst->G = gl::floatToNormalized<4, unsigned char>(src->green);
- dst->B = gl::floatToNormalized<4, unsigned char>(src->blue);
- dst->A = gl::floatToNormalized<4, unsigned char>(src->alpha);
+ dst->RGBA = gl::shiftData<4, 12>(gl::floatToNormalized<4, unsigned short>(src->red)) |
+ gl::shiftData<4, 8>(gl::floatToNormalized<4, unsigned short>(src->green)) |
+ gl::shiftData<4, 4>(gl::floatToNormalized<4, unsigned short>(src->blue)) |
+ gl::shiftData<4, 0>(gl::floatToNormalized<4, unsigned short>(src->alpha));
}
static void average(R4G4B4A4 *dst, const R4G4B4A4 *src1, const R4G4B4A4 *src2)
{
- dst->R = gl::average(src1->R, src2->R);
- dst->G = gl::average(src1->G, src2->G);
- dst->B = gl::average(src1->B, src2->B);
- dst->A = gl::average(src1->A, src2->A);
+ dst->RGBA = gl::shiftData<4, 12>(gl::average(gl::getShiftedData<4, 12>(src1->RGBA), gl::getShiftedData<4, 12>(src2->RGBA))) |
+ gl::shiftData<4, 8>(gl::average(gl::getShiftedData<4, 8>(src1->RGBA), gl::getShiftedData<4, 8>(src2->RGBA))) |
+ gl::shiftData<4, 4>(gl::average(gl::getShiftedData<4, 4>(src1->RGBA), gl::getShiftedData<4, 4>(src2->RGBA))) |
+ gl::shiftData<4, 0>(gl::average(gl::getShiftedData<4, 0>(src1->RGBA), gl::getShiftedData<4, 0>(src2->RGBA)));
}
};
struct A4R4G4B4
{
- unsigned char A : 4;
- unsigned char R : 4;
- unsigned char G : 4;
- unsigned char B : 4;
+ unsigned short ARGB;
static void readColor(gl::ColorF *dst, const A4R4G4B4 *src)
{
- dst->red = gl::normalizedToFloat<4>(src->R);
- dst->green = gl::normalizedToFloat<4>(src->G);
- dst->blue = gl::normalizedToFloat<4>(src->B);
- dst->alpha = gl::normalizedToFloat<4>(src->A);
+ dst->alpha = gl::normalizedToFloat<4>(gl::getShiftedData<4, 12>(src->ARGB));
+ dst->red = gl::normalizedToFloat<4>(gl::getShiftedData<4, 8>(src->ARGB));
+ dst->green = gl::normalizedToFloat<4>(gl::getShiftedData<4, 4>(src->ARGB));
+ dst->blue = gl::normalizedToFloat<4>(gl::getShiftedData<4, 0>(src->ARGB));
}
static void writeColor(A4R4G4B4 *dst, const gl::ColorF *src)
{
- dst->R = gl::floatToNormalized<4, unsigned char>(src->red);
- dst->G = gl::floatToNormalized<4, unsigned char>(src->green);
- dst->B = gl::floatToNormalized<4, unsigned char>(src->blue);
- dst->A = gl::floatToNormalized<4, unsigned char>(src->alpha);
+ dst->ARGB = gl::shiftData<4, 12>(gl::floatToNormalized<4, unsigned short>(src->alpha)) |
+ gl::shiftData<4, 8>(gl::floatToNormalized<4, unsigned short>(src->red)) |
+ gl::shiftData<4, 4>(gl::floatToNormalized<4, unsigned short>(src->green)) |
+ gl::shiftData<4, 0>(gl::floatToNormalized<4, unsigned short>(src->blue));
}
static void average(A4R4G4B4 *dst, const A4R4G4B4 *src1, const A4R4G4B4 *src2)
{
- dst->R = gl::average(src1->R, src2->R);
- dst->G = gl::average(src1->G, src2->G);
- dst->B = gl::average(src1->B, src2->B);
- dst->A = gl::average(src1->A, src2->A);
- }
-};
-
-struct B4G4R4A4
-{
- unsigned char B : 4;
- unsigned char G : 4;
- unsigned char R : 4;
- unsigned char A : 4;
-
- static void readColor(gl::ColorF *dst, const B4G4R4A4 *src)
- {
- dst->red = gl::normalizedToFloat<4>(src->R);
- dst->green = gl::normalizedToFloat<4>(src->G);
- dst->blue = gl::normalizedToFloat<4>(src->B);
- dst->alpha = gl::normalizedToFloat<4>(src->A);
- }
-
- static void writeColor(B4G4R4A4 *dst, const gl::ColorF *src)
- {
- dst->R = gl::floatToNormalized<4, unsigned char>(src->red);
- dst->G = gl::floatToNormalized<4, unsigned char>(src->green);
- dst->B = gl::floatToNormalized<4, unsigned char>(src->blue);
- dst->A = gl::floatToNormalized<4, unsigned char>(src->alpha);
- }
-
- static void average(B4G4R4A4 *dst, const B4G4R4A4 *src1, const B4G4R4A4 *src2)
- {
- dst->R = gl::average(src1->R, src2->R);
- dst->G = gl::average(src1->G, src2->G);
- dst->B = gl::average(src1->B, src2->B);
- dst->A = gl::average(src1->A, src2->A);
+ dst->ARGB = gl::shiftData<4, 12>(gl::average(gl::getShiftedData<4, 12>(src1->ARGB), gl::getShiftedData<4, 12>(src2->ARGB))) |
+ gl::shiftData<4, 8>(gl::average(gl::getShiftedData<4, 8>(src1->ARGB), gl::getShiftedData<4, 8>(src2->ARGB))) |
+ gl::shiftData<4, 4>(gl::average(gl::getShiftedData<4, 4>(src1->ARGB), gl::getShiftedData<4, 4>(src2->ARGB))) |
+ gl::shiftData<4, 0>(gl::average(gl::getShiftedData<4, 0>(src1->ARGB), gl::getShiftedData<4, 0>(src2->ARGB)));
}
};
@@ -1013,7 +981,7 @@ struct R8S
static void average(R8S *dst, const R8S *src1, const R8S *src2)
{
- dst->R = gl::average(src1->R, src2->R);
+ dst->R = static_cast<char>(gl::average(src1->R, src2->R));
}
};
@@ -1052,8 +1020,8 @@ struct R8G8S
static void average(R8G8S *dst, const R8G8S *src1, const R8G8S *src2)
{
- dst->R = gl::average(src1->R, src2->R);
- dst->G = gl::average(src1->G, src2->G);
+ dst->R = static_cast<char>(gl::average(src1->R, src2->R));
+ dst->G = static_cast<char>(gl::average(src1->G, src2->G));
}
};
@@ -1095,9 +1063,9 @@ struct R8G8B8S
static void average(R8G8B8S *dst, const R8G8B8S *src1, const R8G8B8S *src2)
{
- dst->R = gl::average(src1->R, src2->R);
- dst->G = gl::average(src1->G, src2->G);
- dst->B = gl::average(src1->B, src2->B);
+ dst->R = static_cast<char>(gl::average(src1->R, src2->R));
+ dst->G = static_cast<char>(gl::average(src1->G, src2->G));
+ dst->B = static_cast<char>(gl::average(src1->B, src2->B));
}
};
@@ -1142,10 +1110,10 @@ struct R8G8B8A8S
static void average(R8G8B8A8S *dst, const R8G8B8A8S *src1, const R8G8B8A8S *src2)
{
- dst->R = gl::average(src1->R, src2->R);
- dst->G = gl::average(src1->G, src2->G);
- dst->B = gl::average(src1->B, src2->B);
- dst->A = gl::average(src1->A, src2->A);
+ dst->R = static_cast<char>(gl::average(src1->R, src2->R));
+ dst->G = static_cast<char>(gl::average(src1->G, src2->G));
+ dst->B = static_cast<char>(gl::average(src1->B, src2->B));
+ dst->A = static_cast<char>(gl::average(src1->A, src2->A));
}
};
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimage.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimage.cpp
index 172832b3e7..b9b9e5e4ab 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimage.cpp
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimage.cpp
@@ -298,9 +298,9 @@ void LoadR5G6B5ToBGRA8(size_t width, size_t height, size_t depth,
for (size_t x = 0; x < width; x++)
{
uint16_t rgb = source[x];
- dest[4 * x + 0] = ((rgb & 0x001F) << 3) | ((rgb & 0x001F) >> 2);
- dest[4 * x + 1] = ((rgb & 0x07E0) >> 3) | ((rgb & 0x07E0) >> 9);
- dest[4 * x + 2] = ((rgb & 0xF800) >> 8) | ((rgb & 0xF800) >> 13);
+ dest[4 * x + 0] = static_cast<uint8_t>(((rgb & 0x001F) << 3) | ((rgb & 0x001F) >> 2));
+ dest[4 * x + 1] = static_cast<uint8_t>(((rgb & 0x07E0) >> 3) | ((rgb & 0x07E0) >> 9));
+ dest[4 * x + 2] = static_cast<uint8_t>(((rgb & 0xF800) >> 8) | ((rgb & 0xF800) >> 13));
dest[4 * x + 3] = 0xFF;
}
}
@@ -320,9 +320,9 @@ void LoadR5G6B5ToRGBA8(size_t width, size_t height, size_t depth,
for (size_t x = 0; x < width; x++)
{
uint16_t rgb = source[x];
- dest[4 * x + 0] = ((rgb & 0xF800) >> 8) | ((rgb & 0xF800) >> 13);
- dest[4 * x + 1] = ((rgb & 0x07E0) >> 3) | ((rgb & 0x07E0) >> 9);
- dest[4 * x + 2] = ((rgb & 0x001F) << 3) | ((rgb & 0x001F) >> 2);
+ dest[4 * x + 0] = static_cast<uint8_t>(((rgb & 0xF800) >> 8) | ((rgb & 0xF800) >> 13));
+ dest[4 * x + 1] = static_cast<uint8_t>(((rgb & 0x07E0) >> 3) | ((rgb & 0x07E0) >> 9));
+ dest[4 * x + 2] = static_cast<uint8_t>(((rgb & 0x001F) << 3) | ((rgb & 0x001F) >> 2));
dest[4 * x + 3] = 0xFF;
}
}
@@ -348,6 +348,24 @@ void LoadRGBA8ToBGRA8(size_t width, size_t height, size_t depth,
}
}
+void LoadRGBA4ToARGB4(size_t width, size_t height, size_t depth,
+ const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch,
+ uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch)
+{
+ for (size_t z = 0; z < depth; z++)
+ {
+ for (size_t y = 0; y < height; y++)
+ {
+ const uint16_t *source = OffsetDataPointer<uint16_t>(input, y, z, inputRowPitch, inputDepthPitch);
+ uint16_t *dest = OffsetDataPointer<uint16_t>(output, y, z, outputRowPitch, outputDepthPitch);
+ for (size_t x = 0; x < width; x++)
+ {
+ dest[x] = ANGLE_ROTR16(source[x], 4);
+ }
+ }
+ }
+}
+
void LoadRGBA4ToBGRA8(size_t width, size_t height, size_t depth,
const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch,
uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch)
@@ -361,10 +379,10 @@ void LoadRGBA4ToBGRA8(size_t width, size_t height, size_t depth,
for (size_t x = 0; x < width; x++)
{
uint16_t rgba = source[x];
- dest[4 * x + 0] = ((rgba & 0x00F0) << 0) | ((rgba & 0x00F0) >> 4);
- dest[4 * x + 1] = ((rgba & 0x0F00) >> 4) | ((rgba & 0x0F00) >> 8);
- dest[4 * x + 2] = ((rgba & 0xF000) >> 8) | ((rgba & 0xF000) >> 12);
- dest[4 * x + 3] = ((rgba & 0x000F) << 4) | ((rgba & 0x000F) >> 0);
+ dest[4 * x + 0] = static_cast<uint8_t>(((rgba & 0x00F0) << 0) | ((rgba & 0x00F0) >> 4));
+ dest[4 * x + 1] = static_cast<uint8_t>(((rgba & 0x0F00) >> 4) | ((rgba & 0x0F00) >> 8));
+ dest[4 * x + 2] = static_cast<uint8_t>(((rgba & 0xF000) >> 8) | ((rgba & 0xF000) >> 12));
+ dest[4 * x + 3] = static_cast<uint8_t>(((rgba & 0x000F) << 4) | ((rgba & 0x000F) >> 0));
}
}
}
@@ -383,10 +401,10 @@ void LoadRGBA4ToRGBA8(size_t width, size_t height, size_t depth,
for (size_t x = 0; x < width; x++)
{
uint16_t rgba = source[x];
- dest[4 * x + 0] = ((rgba & 0xF000) >> 8) | ((rgba & 0xF000) >> 12);
- dest[4 * x + 1] = ((rgba & 0x0F00) >> 4) | ((rgba & 0x0F00) >> 8);
- dest[4 * x + 2] = ((rgba & 0x00F0) << 0) | ((rgba & 0x00F0) >> 4);
- dest[4 * x + 3] = ((rgba & 0x000F) << 4) | ((rgba & 0x000F) >> 0);
+ dest[4 * x + 0] = static_cast<uint8_t>(((rgba & 0xF000) >> 8) | ((rgba & 0xF000) >> 12));
+ dest[4 * x + 1] = static_cast<uint8_t>(((rgba & 0x0F00) >> 4) | ((rgba & 0x0F00) >> 8));
+ dest[4 * x + 2] = static_cast<uint8_t>(((rgba & 0x00F0) << 0) | ((rgba & 0x00F0) >> 4));
+ dest[4 * x + 3] = static_cast<uint8_t>(((rgba & 0x000F) << 4) | ((rgba & 0x000F) >> 0));
}
}
}
@@ -405,10 +423,28 @@ void LoadBGRA4ToBGRA8(size_t width, size_t height, size_t depth,
for (size_t x = 0; x < width; x++)
{
uint16_t bgra = source[x];
- dest[4 * x + 0] = ((bgra & 0xF000) >> 8) | ((bgra & 0xF000) >> 12);
- dest[4 * x + 1] = ((bgra & 0x0F00) >> 4) | ((bgra & 0x0F00) >> 8);
- dest[4 * x + 2] = ((bgra & 0x00F0) << 0) | ((bgra & 0x00F0) >> 4);
- dest[4 * x + 3] = ((bgra & 0x000F) << 4) | ((bgra & 0x000F) >> 0);
+ dest[4 * x + 0] = static_cast<uint8_t>(((bgra & 0xF000) >> 8) | ((bgra & 0xF000) >> 12));
+ dest[4 * x + 1] = static_cast<uint8_t>(((bgra & 0x0F00) >> 4) | ((bgra & 0x0F00) >> 8));
+ dest[4 * x + 2] = static_cast<uint8_t>(((bgra & 0x00F0) << 0) | ((bgra & 0x00F0) >> 4));
+ dest[4 * x + 3] = static_cast<uint8_t>(((bgra & 0x000F) << 4) | ((bgra & 0x000F) >> 0));
+ }
+ }
+ }
+}
+
+void LoadRGB5A1ToA1RGB5(size_t width, size_t height, size_t depth,
+ const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch,
+ uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch)
+{
+ for (size_t z = 0; z < depth; z++)
+ {
+ for (size_t y = 0; y < height; y++)
+ {
+ const uint16_t *source = OffsetDataPointer<uint16_t>(input, y, z, inputRowPitch, inputDepthPitch);
+ uint16_t *dest = OffsetDataPointer<uint16_t>(output, y, z, outputRowPitch, outputDepthPitch);
+ for (size_t x = 0; x < width; x++)
+ {
+ dest[x] = ANGLE_ROTR16(source[x], 1);
}
}
}
@@ -427,10 +463,10 @@ void LoadRGB5A1ToBGRA8(size_t width, size_t height, size_t depth,
for (size_t x = 0; x < width; x++)
{
uint16_t rgba = source[x];
- dest[4 * x + 0] = ((rgba & 0x003E) << 2) | ((rgba & 0x003E) >> 3);
- dest[4 * x + 1] = ((rgba & 0x07C0) >> 3) | ((rgba & 0x07C0) >> 8);
- dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
- dest[4 * x + 3] = (rgba & 0x0001) ? 0xFF : 0;
+ dest[4 * x + 0] = static_cast<uint8_t>(((rgba & 0x003E) << 2) | ((rgba & 0x003E) >> 3));
+ dest[4 * x + 1] = static_cast<uint8_t>(((rgba & 0x07C0) >> 3) | ((rgba & 0x07C0) >> 8));
+ dest[4 * x + 2] = static_cast<uint8_t>(((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13));
+ dest[4 * x + 3] = static_cast<uint8_t>((rgba & 0x0001) ? 0xFF : 0);
}
}
}
@@ -449,16 +485,15 @@ void LoadRGB5A1ToRGBA8(size_t width, size_t height, size_t depth,
for (size_t x = 0; x < width; x++)
{
uint16_t rgba = source[x];
- dest[4 * x + 0] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
- dest[4 * x + 1] = ((rgba & 0x07C0) >> 3) | ((rgba & 0x07C0) >> 8);
- dest[4 * x + 2] = ((rgba & 0x003E) << 2) | ((rgba & 0x003E) >> 3);
- dest[4 * x + 3] = (rgba & 0x0001) ? 0xFF : 0;
+ dest[4 * x + 0] = static_cast<uint8_t>(((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13));
+ dest[4 * x + 1] = static_cast<uint8_t>(((rgba & 0x07C0) >> 3) | ((rgba & 0x07C0) >> 8));
+ dest[4 * x + 2] = static_cast<uint8_t>(((rgba & 0x003E) << 2) | ((rgba & 0x003E) >> 3));
+ dest[4 * x + 3] = static_cast<uint8_t>((rgba & 0x0001) ? 0xFF : 0);
}
}
}
}
-
void LoadBGR5A1ToBGRA8(size_t width, size_t height, size_t depth,
const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch,
uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch)
@@ -472,10 +507,10 @@ void LoadBGR5A1ToBGRA8(size_t width, size_t height, size_t depth,
for (size_t x = 0; x < width; x++)
{
uint16_t bgra = source[x];
- dest[4 * x + 0] = ((bgra & 0xF800) >> 8) | ((bgra & 0xF800) >> 13);
- dest[4 * x + 1] = ((bgra & 0x07C0) >> 3) | ((bgra & 0x07C0) >> 8);
- dest[4 * x + 2] = ((bgra & 0x003E) << 2) | ((bgra & 0x003E) >> 3);
- dest[4 * x + 3] = (bgra & 0x0001) ? 0xFF : 0;
+ dest[4 * x + 0] = static_cast<uint8_t>(((bgra & 0xF800) >> 8) | ((bgra & 0xF800) >> 13));
+ dest[4 * x + 1] = static_cast<uint8_t>(((bgra & 0x07C0) >> 3) | ((bgra & 0x07C0) >> 8));
+ dest[4 * x + 2] = static_cast<uint8_t>(((bgra & 0x003E) << 2) | ((bgra & 0x003E) >> 3));
+ dest[4 * x + 3] = static_cast<uint8_t>((bgra & 0x0001) ? 0xFF : 0);
}
}
}
@@ -494,10 +529,10 @@ void LoadRGB10A2ToRGBA8(size_t width, size_t height, size_t depth,
for (size_t x = 0; x < width; x++)
{
uint32_t rgba = source[x];
- dest[4 * x + 0] = (rgba & 0x000003FF) >> 2;
- dest[4 * x + 1] = (rgba & 0x000FFC00) >> 12;
- dest[4 * x + 2] = (rgba & 0x3FF00000) >> 22;
- dest[4 * x + 3] = ((rgba & 0xC0000000) >> 30) * 0x55;
+ dest[4 * x + 0] = static_cast<uint8_t>((rgba & 0x000003FF) >> 2);
+ dest[4 * x + 1] = static_cast<uint8_t>((rgba & 0x000FFC00) >> 12);
+ dest[4 * x + 2] = static_cast<uint8_t>((rgba & 0x3FF00000) >> 22);
+ dest[4 * x + 3] = static_cast<uint8_t>(((rgba & 0xC0000000) >> 30) * 0x55);
}
}
}
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimage.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimage.h
index 6967dc868e..6c5118365e 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimage.h
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimage.h
@@ -96,6 +96,10 @@ void LoadRGBA8ToBGRA8(size_t width, size_t height, size_t depth,
const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch,
uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch);
+void LoadRGBA4ToARGB4(size_t width, size_t height, size_t depth,
+ const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch,
+ uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch);
+
void LoadRGBA4ToBGRA8(size_t width, size_t height, size_t depth,
const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch,
uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch);
@@ -108,6 +112,10 @@ void LoadBGRA4ToBGRA8(size_t width, size_t height, size_t depth,
const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch,
uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch);
+void LoadRGB5A1ToA1RGB5(size_t width, size_t height, size_t depth,
+ const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch,
+ uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch);
+
void LoadRGB5A1ToBGRA8(size_t width, size_t height, size_t depth,
const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch,
uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch);
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimage_etc.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimage_etc.cpp
new file mode 100644
index 0000000000..26a3b32ce0
--- /dev/null
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimage_etc.cpp
@@ -0,0 +1,1435 @@
+//
+// Copyright (c) 2013-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.
+//
+
+// loadimage_etc.cpp: Decodes ETC and EAC encoded textures.
+
+#include "libANGLE/renderer/d3d/loadimage_etc.h"
+
+#include "libANGLE/renderer/d3d/loadimage.h"
+#include "libANGLE/renderer/d3d/imageformats.h"
+
+namespace rx
+{
+namespace
+{
+// Table 3.17.2 sorted according to table 3.17.3
+// clang-format off
+static const int intensityModifierDefault[][4] =
+{
+ { 2, 8, -2, -8 },
+ { 5, 17, -5, -17 },
+ { 9, 29, -9, -29 },
+ { 13, 42, -13, -42 },
+ { 18, 60, -18, -60 },
+ { 24, 80, -24, -80 },
+ { 33, 106, -33, -106 },
+ { 47, 183, -47, -183 },
+};
+// clang-format on
+
+// Table C.12, intensity modifier for non opaque punchthrough alpha
+// clang-format off
+static const int intensityModifierNonOpaque[][4] =
+{
+ { 0, 8, 0, -8 },
+ { 0, 17, 0, -17 },
+ { 0, 29, 0, -29 },
+ { 0, 42, 0, -42 },
+ { 0, 60, 0, -60 },
+ { 0, 80, 0, -80 },
+ { 0, 106, 0, -106 },
+ { 0, 183, 0, -183 },
+};
+// clang-format on
+
+// Table C.7, mapping from pixel index values to modifier value orders
+// clang-format off
+static const int valueMappingTable[] =
+{
+ 2, 3, 1, 0
+};
+// clang-format on
+
+struct ETC2Block
+{
+ // Decodes unsigned single or dual channel block to bytes
+ void decodeAsSingleChannel(uint8_t *dest,
+ size_t x,
+ size_t y,
+ size_t w,
+ size_t h,
+ size_t destPixelStride,
+ size_t destRowPitch,
+ bool isSigned) const
+ {
+ for (size_t j = 0; j < 4 && (y + j) < h; j++)
+ {
+ uint8_t *row = dest + (j * destRowPitch);
+ for (size_t i = 0; i < 4 && (x + i) < w; i++)
+ {
+ uint8_t *pixel = row + (i * destPixelStride);
+ if (isSigned)
+ {
+ *pixel = clampSByte(getSingleChannel(i, j, isSigned));
+ }
+ else
+ {
+ *pixel = clampByte(getSingleChannel(i, j, isSigned));
+ }
+ }
+ }
+ }
+
+ // Decodes RGB block to rgba8
+ void decodeAsRGB(uint8_t *dest,
+ size_t x,
+ size_t y,
+ size_t w,
+ size_t h,
+ size_t destRowPitch,
+ const uint8_t alphaValues[4][4],
+ bool punchThroughAlpha) const
+ {
+ bool opaqueBit = u.idht.mode.idm.diffbit;
+ bool nonOpaquePunchThroughAlpha = punchThroughAlpha && !opaqueBit;
+ // Select mode
+ if (u.idht.mode.idm.diffbit || punchThroughAlpha)
+ {
+ const auto &block = u.idht.mode.idm.colors.diff;
+ int r = (block.R + block.dR);
+ int g = (block.G + block.dG);
+ int b = (block.B + block.dB);
+ if (r < 0 || r > 31)
+ {
+ decodeTBlock(dest, x, y, w, h, destRowPitch, alphaValues,
+ nonOpaquePunchThroughAlpha);
+ }
+ else if (g < 0 || g > 31)
+ {
+ decodeHBlock(dest, x, y, w, h, destRowPitch, alphaValues,
+ nonOpaquePunchThroughAlpha);
+ }
+ else if (b < 0 || b > 31)
+ {
+ decodePlanarBlock(dest, x, y, w, h, destRowPitch, alphaValues);
+ }
+ else
+ {
+ decodeDifferentialBlock(dest, x, y, w, h, destRowPitch, alphaValues,
+ nonOpaquePunchThroughAlpha);
+ }
+ }
+ else
+ {
+ decodeIndividualBlock(dest, x, y, w, h, destRowPitch, alphaValues,
+ nonOpaquePunchThroughAlpha);
+ }
+ }
+
+ // Transcodes RGB block to BC1
+ void transcodeAsBC1(uint8_t *dest,
+ size_t x,
+ size_t y,
+ size_t w,
+ size_t h,
+ const uint8_t alphaValues[4][4],
+ bool punchThroughAlpha) const
+ {
+ bool opaqueBit = u.idht.mode.idm.diffbit;
+ bool nonOpaquePunchThroughAlpha = punchThroughAlpha && !opaqueBit;
+ // Select mode
+ if (u.idht.mode.idm.diffbit || punchThroughAlpha)
+ {
+ const auto &block = u.idht.mode.idm.colors.diff;
+ int r = (block.R + block.dR);
+ int g = (block.G + block.dG);
+ int b = (block.B + block.dB);
+ if (r < 0 || r > 31)
+ {
+ transcodeTBlockToBC1(dest, x, y, w, h, alphaValues, nonOpaquePunchThroughAlpha);
+ }
+ else if (g < 0 || g > 31)
+ {
+ transcodeHBlockToBC1(dest, x, y, w, h, alphaValues, nonOpaquePunchThroughAlpha);
+ }
+ else if (b < 0 || b > 31)
+ {
+ transcodePlanarBlockToBC1(dest, x, y, w, h, alphaValues);
+ }
+ else
+ {
+ transcodeDifferentialBlockToBC1(dest, x, y, w, h, alphaValues,
+ nonOpaquePunchThroughAlpha);
+ }
+ }
+ else
+ {
+ transcodeIndividualBlockToBC1(dest, x, y, w, h, alphaValues,
+ nonOpaquePunchThroughAlpha);
+ }
+ }
+
+ private:
+ union
+ {
+ // Individual, differential, H and T modes
+ struct
+ {
+ union
+ {
+ // Individual and differential modes
+ struct
+ {
+ union
+ {
+ struct // Individual colors
+ {
+ unsigned char R2 : 4;
+ unsigned char R1 : 4;
+ unsigned char G2 : 4;
+ unsigned char G1 : 4;
+ unsigned char B2 : 4;
+ unsigned char B1 : 4;
+ } indiv;
+ struct // Differential colors
+ {
+ signed char dR : 3;
+ unsigned char R : 5;
+ signed char dG : 3;
+ unsigned char G : 5;
+ signed char dB : 3;
+ unsigned char B : 5;
+ } diff;
+ } colors;
+ bool flipbit : 1;
+ bool diffbit : 1;
+ unsigned char cw2 : 3;
+ unsigned char cw1 : 3;
+ } idm;
+ // T mode
+ struct
+ {
+ // Byte 1
+ unsigned char TR1b : 2;
+ unsigned char TdummyB : 1;
+ unsigned char TR1a : 2;
+ unsigned char TdummyA : 3;
+ // Byte 2
+ unsigned char TB1 : 4;
+ unsigned char TG1 : 4;
+ // Byte 3
+ unsigned char TG2 : 4;
+ unsigned char TR2 : 4;
+ // Byte 4
+ unsigned char Tdb : 1;
+ bool Tflipbit : 1;
+ unsigned char Tda : 2;
+ unsigned char TB2 : 4;
+ } tm;
+ // H mode
+ struct
+ {
+ // Byte 1
+ unsigned char HG1a : 3;
+ unsigned char HR1 : 4;
+ unsigned char HdummyA : 1;
+ // Byte 2
+ unsigned char HB1b : 2;
+ unsigned char HdummyC : 1;
+ unsigned char HB1a : 1;
+ unsigned char HG1b : 1;
+ unsigned char HdummyB : 3;
+ // Byte 3
+ unsigned char HG2a : 3;
+ unsigned char HR2 : 4;
+ unsigned char HB1c : 1;
+ // Byte 4
+ unsigned char Hdb : 1;
+ bool Hflipbit : 1;
+ unsigned char Hda : 1;
+ unsigned char HB2 : 4;
+ unsigned char HG2b : 1;
+ } hm;
+ } mode;
+ unsigned char pixelIndexMSB[2];
+ unsigned char pixelIndexLSB[2];
+ } idht;
+ // planar mode
+ struct
+ {
+ // Byte 1
+ unsigned char GO1 : 1;
+ unsigned char RO : 6;
+ unsigned char PdummyA : 1;
+ // Byte 2
+ unsigned char BO1 : 1;
+ unsigned char GO2 : 6;
+ unsigned char PdummyB : 1;
+ // Byte 3
+ unsigned char BO3a : 2;
+ unsigned char PdummyD : 1;
+ unsigned char BO2 : 2;
+ unsigned char PdummyC : 3;
+ // Byte 4
+ unsigned char RH2 : 1;
+ bool Pflipbit : 1;
+ unsigned char RH1 : 5;
+ unsigned char BO3b : 1;
+ // Byte 5
+ unsigned char BHa : 1;
+ unsigned char GH : 7;
+ // Byte 6
+ unsigned char RVa : 3;
+ unsigned char BHb : 5;
+ // Byte 7
+ unsigned char GVa : 5;
+ unsigned char RVb : 3;
+ // Byte 8
+ unsigned char BV : 6;
+ unsigned char GVb : 2;
+ } pblk;
+ // Single channel block
+ struct
+ {
+ union
+ {
+ unsigned char us;
+ signed char s;
+ } base_codeword;
+ unsigned char table_index : 4;
+ unsigned char multiplier : 4;
+ unsigned char mc1 : 2;
+ unsigned char mb : 3;
+ unsigned char ma : 3;
+ unsigned char mf1 : 1;
+ unsigned char me : 3;
+ unsigned char md : 3;
+ unsigned char mc2 : 1;
+ unsigned char mh : 3;
+ unsigned char mg : 3;
+ unsigned char mf2 : 2;
+ unsigned char mk1 : 2;
+ unsigned char mj : 3;
+ unsigned char mi : 3;
+ unsigned char mn1 : 1;
+ unsigned char mm : 3;
+ unsigned char ml : 3;
+ unsigned char mk2 : 1;
+ unsigned char mp : 3;
+ unsigned char mo : 3;
+ unsigned char mn2 : 2;
+ } scblk;
+ } u;
+
+ static unsigned char clampByte(int value)
+ {
+ return static_cast<unsigned char>(gl::clamp(value, 0, 255));
+ }
+
+ static signed char clampSByte(int value)
+ {
+ return static_cast<signed char>(gl::clamp(value, -128, 127));
+ }
+
+ static R8G8B8A8 createRGBA(int red, int green, int blue, int alpha)
+ {
+ R8G8B8A8 rgba;
+ rgba.R = clampByte(red);
+ rgba.G = clampByte(green);
+ rgba.B = clampByte(blue);
+ rgba.A = clampByte(alpha);
+ return rgba;
+ }
+
+ static R8G8B8A8 createRGBA(int red, int green, int blue)
+ {
+ return createRGBA(red, green, blue, 255);
+ }
+
+ static int extend_4to8bits(int x) { return (x << 4) | x; }
+ static int extend_5to8bits(int x) { return (x << 3) | (x >> 2); }
+ static int extend_6to8bits(int x) { return (x << 2) | (x >> 4); }
+ static int extend_7to8bits(int x) { return (x << 1) | (x >> 6); }
+
+ void decodeIndividualBlock(uint8_t *dest,
+ size_t x,
+ size_t y,
+ size_t w,
+ size_t h,
+ size_t destRowPitch,
+ const uint8_t alphaValues[4][4],
+ bool nonOpaquePunchThroughAlpha) const
+ {
+ const auto &block = u.idht.mode.idm.colors.indiv;
+ int r1 = extend_4to8bits(block.R1);
+ int g1 = extend_4to8bits(block.G1);
+ int b1 = extend_4to8bits(block.B1);
+ int r2 = extend_4to8bits(block.R2);
+ int g2 = extend_4to8bits(block.G2);
+ int b2 = extend_4to8bits(block.B2);
+ decodeIndividualOrDifferentialBlock(dest, x, y, w, h, destRowPitch, r1, g1, b1, r2, g2, b2,
+ alphaValues, nonOpaquePunchThroughAlpha);
+ }
+
+ void decodeDifferentialBlock(uint8_t *dest,
+ size_t x,
+ size_t y,
+ size_t w,
+ size_t h,
+ size_t destRowPitch,
+ const uint8_t alphaValues[4][4],
+ bool nonOpaquePunchThroughAlpha) const
+ {
+ const auto &block = u.idht.mode.idm.colors.diff;
+ int b1 = extend_5to8bits(block.B);
+ int g1 = extend_5to8bits(block.G);
+ int r1 = extend_5to8bits(block.R);
+ int r2 = extend_5to8bits(block.R + block.dR);
+ int g2 = extend_5to8bits(block.G + block.dG);
+ int b2 = extend_5to8bits(block.B + block.dB);
+ decodeIndividualOrDifferentialBlock(dest, x, y, w, h, destRowPitch, r1, g1, b1, r2, g2, b2,
+ alphaValues, nonOpaquePunchThroughAlpha);
+ }
+
+ void decodeIndividualOrDifferentialBlock(uint8_t *dest,
+ size_t x,
+ size_t y,
+ size_t w,
+ size_t h,
+ size_t destRowPitch,
+ int r1,
+ int g1,
+ int b1,
+ int r2,
+ int g2,
+ int b2,
+ const uint8_t alphaValues[4][4],
+ bool nonOpaquePunchThroughAlpha) const
+ {
+ const auto intensityModifier =
+ nonOpaquePunchThroughAlpha ? intensityModifierNonOpaque : intensityModifierDefault;
+
+ R8G8B8A8 subblockColors0[4];
+ R8G8B8A8 subblockColors1[4];
+ for (size_t modifierIdx = 0; modifierIdx < 4; modifierIdx++)
+ {
+ const int i1 = intensityModifier[u.idht.mode.idm.cw1][modifierIdx];
+ subblockColors0[modifierIdx] = createRGBA(r1 + i1, g1 + i1, b1 + i1);
+
+ const int i2 = intensityModifier[u.idht.mode.idm.cw2][modifierIdx];
+ subblockColors1[modifierIdx] = createRGBA(r2 + i2, g2 + i2, b2 + i2);
+ }
+
+ if (u.idht.mode.idm.flipbit)
+ {
+ uint8_t *curPixel = dest;
+ for (size_t j = 0; j < 2 && (y + j) < h; j++)
+ {
+ R8G8B8A8 *row = reinterpret_cast<R8G8B8A8 *>(curPixel);
+ for (size_t i = 0; i < 4 && (x + i) < w; i++)
+ {
+ row[i] = subblockColors0[getIndex(i, j)];
+ row[i].A = alphaValues[j][i];
+ }
+ curPixel += destRowPitch;
+ }
+ for (size_t j = 2; j < 4 && (y + j) < h; j++)
+ {
+ R8G8B8A8 *row = reinterpret_cast<R8G8B8A8 *>(curPixel);
+ for (size_t i = 0; i < 4 && (x + i) < w; i++)
+ {
+ row[i] = subblockColors1[getIndex(i, j)];
+ row[i].A = alphaValues[j][i];
+ }
+ curPixel += destRowPitch;
+ }
+ }
+ else
+ {
+ uint8_t *curPixel = dest;
+ for (size_t j = 0; j < 4 && (y + j) < h; j++)
+ {
+ R8G8B8A8 *row = reinterpret_cast<R8G8B8A8 *>(curPixel);
+ for (size_t i = 0; i < 2 && (x + i) < w; i++)
+ {
+ row[i] = subblockColors0[getIndex(i, j)];
+ row[i].A = alphaValues[j][i];
+ }
+ for (size_t i = 2; i < 4 && (x + i) < w; i++)
+ {
+ row[i] = subblockColors1[getIndex(i, j)];
+ row[i].A = alphaValues[j][i];
+ }
+ curPixel += destRowPitch;
+ }
+ }
+ if (nonOpaquePunchThroughAlpha)
+ {
+ decodePunchThroughAlphaBlock(dest, x, y, w, h, destRowPitch);
+ }
+ }
+
+ void decodeTBlock(uint8_t *dest,
+ size_t x,
+ size_t y,
+ size_t w,
+ size_t h,
+ size_t destRowPitch,
+ const uint8_t alphaValues[4][4],
+ bool nonOpaquePunchThroughAlpha) const
+ {
+ // Table C.8, distance index for T and H modes
+ const auto &block = u.idht.mode.tm;
+
+ int r1 = extend_4to8bits(block.TR1a << 2 | block.TR1b);
+ int g1 = extend_4to8bits(block.TG1);
+ int b1 = extend_4to8bits(block.TB1);
+ int r2 = extend_4to8bits(block.TR2);
+ int g2 = extend_4to8bits(block.TG2);
+ int b2 = extend_4to8bits(block.TB2);
+
+ static int distance[8] = {3, 6, 11, 16, 23, 32, 41, 64};
+ const int d = distance[block.Tda << 1 | block.Tdb];
+
+ const R8G8B8A8 paintColors[4] = {
+ createRGBA(r1, g1, b1), createRGBA(r2 + d, g2 + d, b2 + d), createRGBA(r2, g2, b2),
+ createRGBA(r2 - d, g2 - d, b2 - d),
+ };
+
+ uint8_t *curPixel = dest;
+ for (size_t j = 0; j < 4 && (y + j) < h; j++)
+ {
+ R8G8B8A8 *row = reinterpret_cast<R8G8B8A8 *>(curPixel);
+ for (size_t i = 0; i < 4 && (x + i) < w; i++)
+ {
+ row[i] = paintColors[getIndex(i, j)];
+ row[i].A = alphaValues[j][i];
+ }
+ curPixel += destRowPitch;
+ }
+
+ if (nonOpaquePunchThroughAlpha)
+ {
+ decodePunchThroughAlphaBlock(dest, x, y, w, h, destRowPitch);
+ }
+ }
+
+ void decodeHBlock(uint8_t *dest,
+ size_t x,
+ size_t y,
+ size_t w,
+ size_t h,
+ size_t destRowPitch,
+ const uint8_t alphaValues[4][4],
+ bool nonOpaquePunchThroughAlpha) const
+ {
+ // Table C.8, distance index for T and H modes
+ const auto &block = u.idht.mode.hm;
+
+ int r1 = extend_4to8bits(block.HR1);
+ int g1 = extend_4to8bits(block.HG1a << 1 | block.HG1b);
+ int b1 = extend_4to8bits(block.HB1a << 3 | block.HB1b << 1 | block.HB1c);
+ int r2 = extend_4to8bits(block.HR2);
+ int g2 = extend_4to8bits(block.HG2a << 1 | block.HG2b);
+ int b2 = extend_4to8bits(block.HB2);
+
+ static const int distance[8] = {3, 6, 11, 16, 23, 32, 41, 64};
+ const int d = distance[(block.Hda << 2) | (block.Hdb << 1) |
+ ((r1 << 16 | g1 << 8 | b1) >= (r2 << 16 | g2 << 8 | b2) ? 1 : 0)];
+
+ const R8G8B8A8 paintColors[4] = {
+ createRGBA(r1 + d, g1 + d, b1 + d), createRGBA(r1 - d, g1 - d, b1 - d),
+ createRGBA(r2 + d, g2 + d, b2 + d), createRGBA(r2 - d, g2 - d, b2 - d),
+ };
+
+ uint8_t *curPixel = dest;
+ for (size_t j = 0; j < 4 && (y + j) < h; j++)
+ {
+ R8G8B8A8 *row = reinterpret_cast<R8G8B8A8 *>(curPixel);
+ for (size_t i = 0; i < 4 && (x + i) < w; i++)
+ {
+ row[i] = paintColors[getIndex(i, j)];
+ row[i].A = alphaValues[j][i];
+ }
+ curPixel += destRowPitch;
+ }
+
+ if (nonOpaquePunchThroughAlpha)
+ {
+ decodePunchThroughAlphaBlock(dest, x, y, w, h, destRowPitch);
+ }
+ }
+
+ void decodePlanarBlock(uint8_t *dest,
+ size_t x,
+ size_t y,
+ size_t w,
+ size_t h,
+ size_t pitch,
+ const uint8_t alphaValues[4][4]) const
+ {
+ int ro = extend_6to8bits(u.pblk.RO);
+ int go = extend_7to8bits(u.pblk.GO1 << 6 | u.pblk.GO2);
+ int bo =
+ extend_6to8bits(u.pblk.BO1 << 5 | u.pblk.BO2 << 3 | u.pblk.BO3a << 1 | u.pblk.BO3b);
+ int rh = extend_6to8bits(u.pblk.RH1 << 1 | u.pblk.RH2);
+ int gh = extend_7to8bits(u.pblk.GH);
+ int bh = extend_6to8bits(u.pblk.BHa << 5 | u.pblk.BHb);
+ int rv = extend_6to8bits(u.pblk.RVa << 3 | u.pblk.RVb);
+ int gv = extend_7to8bits(u.pblk.GVa << 2 | u.pblk.GVb);
+ int bv = extend_6to8bits(u.pblk.BV);
+
+ uint8_t *curPixel = dest;
+ for (size_t j = 0; j < 4 && (y + j) < h; j++)
+ {
+ R8G8B8A8 *row = reinterpret_cast<R8G8B8A8 *>(curPixel);
+
+ int ry = static_cast<int>(j) * (rv - ro) + 2;
+ int gy = static_cast<int>(j) * (gv - go) + 2;
+ int by = static_cast<int>(j) * (bv - bo) + 2;
+ for (size_t i = 0; i < 4 && (x + i) < w; i++)
+ {
+ row[i] = createRGBA(((static_cast<int>(i) * (rh - ro) + ry) >> 2) + ro,
+ ((static_cast<int>(i) * (gh - go) + gy) >> 2) + go,
+ ((static_cast<int>(i) * (bh - bo) + by) >> 2) + bo,
+ alphaValues[j][i]);
+ }
+ curPixel += pitch;
+ }
+ }
+
+ // Index for individual, differential, H and T modes
+ size_t getIndex(size_t x, size_t y) const
+ {
+ size_t bitIndex = x * 4 + y;
+ size_t bitOffset = bitIndex & 7;
+ size_t lsb = (u.idht.pixelIndexLSB[1 - (bitIndex >> 3)] >> bitOffset) & 1;
+ size_t msb = (u.idht.pixelIndexMSB[1 - (bitIndex >> 3)] >> bitOffset) & 1;
+ return (msb << 1) | lsb;
+ }
+
+ void decodePunchThroughAlphaBlock(uint8_t *dest,
+ size_t x,
+ size_t y,
+ size_t w,
+ size_t h,
+ size_t destRowPitch) const
+ {
+ uint8_t *curPixel = dest;
+ for (size_t j = 0; j < 4 && (y + j) < h; j++)
+ {
+ R8G8B8A8 *row = reinterpret_cast<R8G8B8A8 *>(curPixel);
+ for (size_t i = 0; i < 4 && (x + i) < w; i++)
+ {
+ if (getIndex(i, j) == 2) // msb == 1 && lsb == 0
+ {
+ row[i] = createRGBA(0, 0, 0, 0);
+ }
+ }
+ curPixel += destRowPitch;
+ }
+ }
+
+ uint16_t RGB8ToRGB565(const R8G8B8A8 &rgba) const
+ {
+ return (static_cast<uint16_t>(rgba.R >> 3) << 11) |
+ (static_cast<uint16_t>(rgba.G >> 2) << 5) |
+ (static_cast<uint16_t>(rgba.B >> 3) << 0);
+ }
+
+ uint32_t matchBC1Bits(const R8G8B8A8 *rgba,
+ const R8G8B8A8 &minColor,
+ const R8G8B8A8 &maxColor,
+ bool opaque) const
+ {
+ // Project each pixel on the (maxColor, minColor) line to decide which
+ // BC1 code to assign to it.
+
+ uint8_t decodedColors[2][3] = {{maxColor.R, maxColor.G, maxColor.B},
+ {minColor.R, minColor.G, minColor.B}};
+
+ int direction[3];
+ for (int ch = 0; ch < 3; ch++)
+ {
+ direction[ch] = decodedColors[0][ch] - decodedColors[1][ch];
+ }
+
+ int stops[2];
+ for (int i = 0; i < 2; i++)
+ {
+ stops[i] = decodedColors[i][0] * direction[0] + decodedColors[i][1] * direction[1] +
+ decodedColors[i][2] * direction[2];
+ }
+
+ uint32_t bits = 0;
+ if (opaque)
+ {
+ for (int i = 15; i >= 0; i--)
+ {
+ // In opaque mode, the code is from 0 to 3.
+
+ bits <<= 2;
+ const int dot =
+ rgba[i].R * direction[0] + rgba[i].G * direction[1] + rgba[i].B * direction[2];
+ const int factor = gl::clamp(
+ static_cast<int>(
+ (static_cast<float>(dot - stops[1]) / (stops[0] - stops[1])) * 3 + 0.5f),
+ 0, 3);
+ switch (factor)
+ {
+ case 0:
+ bits |= 1;
+ break;
+ case 1:
+ bits |= 3;
+ break;
+ case 2:
+ bits |= 2;
+ break;
+ case 3:
+ default:
+ bits |= 0;
+ break;
+ }
+ }
+ }
+ else
+ {
+ for (int i = 15; i >= 0; i--)
+ {
+ // In non-opaque mode, 3 is for tranparent pixels.
+
+ bits <<= 2;
+ if (0 == rgba[i].A)
+ {
+ bits |= 3;
+ }
+ else
+ {
+ const int dot = rgba[i].R * direction[0] + rgba[i].G * direction[1] +
+ rgba[i].B * direction[2];
+ const int factor = gl::clamp(
+ static_cast<int>(
+ (static_cast<float>(dot - stops[1]) / (stops[0] - stops[1])) * 2 +
+ 0.5f),
+ 0, 2);
+ switch (factor)
+ {
+ case 0:
+ bits |= 0;
+ break;
+ case 1:
+ bits |= 2;
+ break;
+ case 2:
+ default:
+ bits |= 1;
+ break;
+ }
+ }
+ }
+ }
+
+ return bits;
+ }
+
+ void packBC1(void *bc1,
+ const R8G8B8A8 *rgba,
+ R8G8B8A8 &minColor,
+ R8G8B8A8 &maxColor,
+ bool opaque) const
+ {
+ uint32_t bits;
+ uint16_t max16 = RGB8ToRGB565(maxColor);
+ uint16_t min16 = RGB8ToRGB565(minColor);
+ if (max16 != min16)
+ {
+ // Find the best BC1 code for each pixel
+ bits = matchBC1Bits(rgba, minColor, maxColor, opaque);
+ }
+ else
+ {
+ // Same colors, BC1 index 0 is the color in both opaque and transparent mode
+ bits = 0;
+ // BC1 index 3 is transparent
+ if (!opaque)
+ {
+ for (int i = 0; i < 16; i++)
+ {
+ if (0 == rgba[i].A)
+ {
+ bits |= (3 << (i * 2));
+ }
+ }
+ }
+ }
+
+ if (max16 < min16)
+ {
+ std::swap(max16, min16);
+
+ uint32_t xorMask = 0;
+ if (opaque)
+ {
+ // In opaque mode switching the two colors is doing the
+ // following code swaps: 0 <-> 1 and 2 <-> 3. This is
+ // equivalent to flipping the first bit of each code
+ // (5 = 0b0101)
+ xorMask = 0x55555555;
+ }
+ else
+ {
+ // In transparent mode switching the colors is doing the
+ // following code swap: 0 <-> 1. 0xA selects the second bit of
+ // each code, bits >> 1 selects the first bit of the code when
+ // the seconds bit is set (case 2 and 3). We invert all the
+ // non-selected bits, that is the first bit when the code is
+ // 0 or 1.
+ xorMask = ~((bits >> 1) | 0xAAAAAAAA);
+ }
+ bits ^= xorMask;
+ }
+
+ struct BC1Block
+ {
+ uint16_t color0;
+ uint16_t color1;
+ uint32_t bits;
+ };
+
+ // Encode the opaqueness in the order of the two BC1 colors
+ BC1Block *dest = reinterpret_cast<BC1Block *>(bc1);
+ if (opaque)
+ {
+ dest->color0 = max16;
+ dest->color1 = min16;
+ }
+ else
+ {
+ dest->color0 = min16;
+ dest->color1 = max16;
+ }
+ dest->bits = bits;
+ }
+
+ void transcodeIndividualBlockToBC1(uint8_t *dest,
+ size_t x,
+ size_t y,
+ size_t w,
+ size_t h,
+ const uint8_t alphaValues[4][4],
+ bool nonOpaquePunchThroughAlpha) const
+ {
+ const auto &block = u.idht.mode.idm.colors.indiv;
+ int r1 = extend_4to8bits(block.R1);
+ int g1 = extend_4to8bits(block.G1);
+ int b1 = extend_4to8bits(block.B1);
+ int r2 = extend_4to8bits(block.R2);
+ int g2 = extend_4to8bits(block.G2);
+ int b2 = extend_4to8bits(block.B2);
+ transcodeIndividualOrDifferentialBlockToBC1(dest, x, y, w, h, r1, g1, b1, r2, g2, b2,
+ alphaValues, nonOpaquePunchThroughAlpha);
+ }
+
+ void transcodeDifferentialBlockToBC1(uint8_t *dest,
+ size_t x,
+ size_t y,
+ size_t w,
+ size_t h,
+ const uint8_t alphaValues[4][4],
+ bool nonOpaquePunchThroughAlpha) const
+ {
+ const auto &block = u.idht.mode.idm.colors.diff;
+ int b1 = extend_5to8bits(block.B);
+ int g1 = extend_5to8bits(block.G);
+ int r1 = extend_5to8bits(block.R);
+ int r2 = extend_5to8bits(block.R + block.dR);
+ int g2 = extend_5to8bits(block.G + block.dG);
+ int b2 = extend_5to8bits(block.B + block.dB);
+ transcodeIndividualOrDifferentialBlockToBC1(dest, x, y, w, h, r1, g1, b1, r2, g2, b2,
+ alphaValues, nonOpaquePunchThroughAlpha);
+ }
+
+ void decodeSubblock(R8G8B8A8 *rgbaBlock,
+ size_t pixelRange[2][2],
+ size_t x,
+ size_t y,
+ size_t w,
+ size_t h,
+ const uint8_t alphaValues[4][4],
+ bool flipbit,
+ size_t subblockIdx,
+ const R8G8B8A8 subblockColors[2][4]) const
+ {
+ size_t dxBegin = 0;
+ size_t dxEnd = 4;
+ size_t dyBegin = subblockIdx * 2;
+ size_t dyEnd = dyBegin + 2;
+ if (!flipbit)
+ {
+ std::swap(dxBegin, dyBegin);
+ std::swap(dxEnd, dyEnd);
+ }
+
+ for (size_t j = dyBegin; j < dyEnd && (y + j) < h; j++)
+ {
+ R8G8B8A8 *row = &rgbaBlock[j * 4];
+ for (size_t i = dxBegin; i < dxEnd && (x + i) < w; i++)
+ {
+ const size_t pixelIndex = getIndex(i, j);
+ if (valueMappingTable[pixelIndex] < valueMappingTable[pixelRange[subblockIdx][0]])
+ {
+ pixelRange[subblockIdx][0] = pixelIndex;
+ }
+ if (valueMappingTable[pixelIndex] > valueMappingTable[pixelRange[subblockIdx][1]])
+ {
+ pixelRange[subblockIdx][1] = pixelIndex;
+ }
+
+ row[i] = subblockColors[subblockIdx][pixelIndex];
+ row[i].A = alphaValues[j][i];
+ }
+ }
+ }
+
+ void transcodeIndividualOrDifferentialBlockToBC1(uint8_t *dest,
+ size_t x,
+ size_t y,
+ size_t w,
+ size_t h,
+ int r1,
+ int g1,
+ int b1,
+ int r2,
+ int g2,
+ int b2,
+ const uint8_t alphaValues[4][4],
+ bool nonOpaquePunchThroughAlpha) const
+ {
+ // A BC1 block has 2 endpoints, pixels is encoded as linear
+ // interpolations of them. A ETC1/ETC2 individual or differential block
+ // has 2 subblocks. Each subblock has one color and a modifier. We
+ // compute the max intensity and min intensity pixel values to use as
+ // our two BC1 endpoints and then map pixels to BC1 by projecting on the
+ // line between the two endpoints and choosing the right fraction.
+ //
+ // In the future, we have 2 potential improvements to this algorithm.
+ // 1. We don't actually need to decode ETC blocks to RGBs. Instead,
+ // the subblock colors and pixel indices alreay contains enough
+ // information for transcode. A direct mapping would be more
+ // efficient here.
+ // 2. Currently the BC1 endpoints come from the max and min intensity
+ // of ETC colors. A principal component analysis (PCA) on them might
+ // give us better quality results, with limited costs
+
+ const auto intensityModifier =
+ nonOpaquePunchThroughAlpha ? intensityModifierNonOpaque : intensityModifierDefault;
+
+ // Compute the colors that pixels can have in each subblock both for
+ // the decoding of the RGBA data and BC1 encoding
+ R8G8B8A8 subblockColors[2][4];
+ for (size_t modifierIdx = 0; modifierIdx < 4; modifierIdx++)
+ {
+ const int i1 = intensityModifier[u.idht.mode.idm.cw1][modifierIdx];
+ subblockColors[0][modifierIdx] = createRGBA(r1 + i1, g1 + i1, b1 + i1);
+
+ const int i2 = intensityModifier[u.idht.mode.idm.cw2][modifierIdx];
+ subblockColors[1][modifierIdx] = createRGBA(r2 + i2, g2 + i2, b2 + i2);
+ }
+
+ // 1 and 3 are the argmax and argmin of valueMappingTable
+ size_t pixelRange[2][2] = {{1, 3}, {1, 3}};
+ R8G8B8A8 rgbaBlock[16];
+ // Decode the block in rgbaBlock and store the inverse valueTableMapping
+ // of {min(modifier index), max(modifier index)}
+ for (size_t blockIdx = 0; blockIdx < 2; blockIdx++)
+ {
+ decodeSubblock(rgbaBlock, pixelRange, x, y, w, h, alphaValues, u.idht.mode.idm.flipbit,
+ blockIdx, subblockColors);
+ }
+ if (nonOpaquePunchThroughAlpha)
+ {
+ decodePunchThroughAlphaBlock(reinterpret_cast<uint8_t *>(rgbaBlock), x, y, w, h,
+ sizeof(R8G8B8A8) * 4);
+ }
+
+ // Get the "min" and "max" pixel colors that have been used.
+ R8G8B8A8 minColor;
+ const R8G8B8A8 &minColor0 = subblockColors[0][pixelRange[0][0]];
+ const R8G8B8A8 &minColor1 = subblockColors[1][pixelRange[1][0]];
+ if (minColor0.R + minColor0.G + minColor0.B < minColor1.R + minColor1.G + minColor1.B)
+ {
+ minColor = minColor0;
+ }
+ else
+ {
+ minColor = minColor1;
+ }
+
+ R8G8B8A8 maxColor;
+ const R8G8B8A8 &maxColor0 = subblockColors[0][pixelRange[0][1]];
+ const R8G8B8A8 &maxColor1 = subblockColors[1][pixelRange[1][1]];
+ if (maxColor0.R + maxColor0.G + maxColor0.B < maxColor1.R + maxColor1.G + maxColor1.B)
+ {
+ maxColor = maxColor1;
+ }
+ else
+ {
+ maxColor = maxColor0;
+ }
+
+ packBC1(dest, rgbaBlock, minColor, maxColor, !nonOpaquePunchThroughAlpha);
+ }
+
+ void transcodeTBlockToBC1(uint8_t *dest,
+ size_t x,
+ size_t y,
+ size_t w,
+ size_t h,
+ const uint8_t alphaValues[4][4],
+ bool nonOpaquePunchThroughAlpha) const
+ {
+ // TODO (mgong): Will be implemented soon
+ UNIMPLEMENTED();
+ }
+
+ void transcodeHBlockToBC1(uint8_t *dest,
+ size_t x,
+ size_t y,
+ size_t w,
+ size_t h,
+ const uint8_t alphaValues[4][4],
+ bool nonOpaquePunchThroughAlpha) const
+ {
+ // TODO (mgong): Will be implemented soon
+ UNIMPLEMENTED();
+ }
+
+ void transcodePlanarBlockToBC1(uint8_t *dest,
+ size_t x,
+ size_t y,
+ size_t w,
+ size_t h,
+ const uint8_t alphaValues[4][4]) const
+ {
+ // TODO (mgong): Will be implemented soon
+ UNIMPLEMENTED();
+ }
+
+ // Single channel utility functions
+ int getSingleChannel(size_t x, size_t y, bool isSigned) const
+ {
+ int codeword = isSigned ? u.scblk.base_codeword.s : u.scblk.base_codeword.us;
+ return codeword + getSingleChannelModifier(x, y) * u.scblk.multiplier;
+ }
+
+ int getSingleChannelIndex(size_t x, size_t y) const
+ {
+ ASSERT(x < 4 && y < 4);
+
+ // clang-format off
+ switch (x * 4 + y)
+ {
+ case 0: return u.scblk.ma;
+ case 1: return u.scblk.mb;
+ case 2: return u.scblk.mc1 << 1 | u.scblk.mc2;
+ case 3: return u.scblk.md;
+ case 4: return u.scblk.me;
+ case 5: return u.scblk.mf1 << 2 | u.scblk.mf2;
+ case 6: return u.scblk.mg;
+ case 7: return u.scblk.mh;
+ case 8: return u.scblk.mi;
+ case 9: return u.scblk.mj;
+ case 10: return u.scblk.mk1 << 1 | u.scblk.mk2;
+ case 11: return u.scblk.ml;
+ case 12: return u.scblk.mm;
+ case 13: return u.scblk.mn1 << 2 | u.scblk.mn2;
+ case 14: return u.scblk.mo;
+ case 15: return u.scblk.mp;
+ default: UNREACHABLE(); return 0;
+ }
+ // clang-format on
+ }
+
+ int getSingleChannelModifier(size_t x, size_t y) const
+ {
+ // clang-format off
+ static const int modifierTable[16][8] =
+ {
+ { -3, -6, -9, -15, 2, 5, 8, 14 },
+ { -3, -7, -10, -13, 2, 6, 9, 12 },
+ { -2, -5, -8, -13, 1, 4, 7, 12 },
+ { -2, -4, -6, -13, 1, 3, 5, 12 },
+ { -3, -6, -8, -12, 2, 5, 7, 11 },
+ { -3, -7, -9, -11, 2, 6, 8, 10 },
+ { -4, -7, -8, -11, 3, 6, 7, 10 },
+ { -3, -5, -8, -11, 2, 4, 7, 10 },
+ { -2, -6, -8, -10, 1, 5, 7, 9 },
+ { -2, -5, -8, -10, 1, 4, 7, 9 },
+ { -2, -4, -8, -10, 1, 3, 7, 9 },
+ { -2, -5, -7, -10, 1, 4, 6, 9 },
+ { -3, -4, -7, -10, 2, 3, 6, 9 },
+ { -1, -2, -3, -10, 0, 1, 2, 9 },
+ { -4, -6, -8, -9, 3, 5, 7, 8 },
+ { -3, -5, -7, -9, 2, 4, 6, 8 }
+ };
+ // clang-format on
+
+ return modifierTable[u.scblk.table_index][getSingleChannelIndex(x, y)];
+ }
+};
+
+// clang-format off
+static const uint8_t DefaultETCAlphaValues[4][4] =
+{
+ { 255, 255, 255, 255 },
+ { 255, 255, 255, 255 },
+ { 255, 255, 255, 255 },
+ { 255, 255, 255, 255 },
+};
+// clang-format on
+
+void LoadR11EACToR8(size_t width,
+ size_t height,
+ size_t depth,
+ const uint8_t *input,
+ size_t inputRowPitch,
+ size_t inputDepthPitch,
+ uint8_t *output,
+ size_t outputRowPitch,
+ size_t outputDepthPitch,
+ bool isSigned)
+{
+ for (size_t z = 0; z < depth; z++)
+ {
+ for (size_t y = 0; y < height; y += 4)
+ {
+ const ETC2Block *sourceRow =
+ OffsetDataPointer<ETC2Block>(input, y / 4, z, inputRowPitch, inputDepthPitch);
+ uint8_t *destRow =
+ OffsetDataPointer<uint8_t>(output, y, z, outputRowPitch, outputDepthPitch);
+
+ for (size_t x = 0; x < width; x += 4)
+ {
+ const ETC2Block *sourceBlock = sourceRow + (x / 4);
+ uint8_t *destPixels = destRow + x;
+
+ sourceBlock->decodeAsSingleChannel(destPixels, x, y, width, height, 1,
+ outputRowPitch, isSigned);
+ }
+ }
+ }
+}
+
+void LoadRG11EACToRG8(size_t width,
+ size_t height,
+ size_t depth,
+ const uint8_t *input,
+ size_t inputRowPitch,
+ size_t inputDepthPitch,
+ uint8_t *output,
+ size_t outputRowPitch,
+ size_t outputDepthPitch,
+ bool isSigned)
+{
+ for (size_t z = 0; z < depth; z++)
+ {
+ for (size_t y = 0; y < height; y += 4)
+ {
+ const ETC2Block *sourceRow =
+ OffsetDataPointer<ETC2Block>(input, y / 4, z, inputRowPitch, inputDepthPitch);
+ uint8_t *destRow =
+ OffsetDataPointer<uint8_t>(output, y, z, outputRowPitch, outputDepthPitch);
+
+ for (size_t x = 0; x < width; x += 4)
+ {
+ uint8_t *destPixelsRed = destRow + (x * 2);
+ const ETC2Block *sourceBlockRed = sourceRow + (x / 2);
+ sourceBlockRed->decodeAsSingleChannel(destPixelsRed, x, y, width, height, 2,
+ outputRowPitch, isSigned);
+
+ uint8_t *destPixelsGreen = destPixelsRed + 1;
+ const ETC2Block *sourceBlockGreen = sourceBlockRed + 1;
+ sourceBlockGreen->decodeAsSingleChannel(destPixelsGreen, x, y, width, height, 2,
+ outputRowPitch, isSigned);
+ }
+ }
+ }
+}
+
+void LoadETC2RGB8ToRGBA8(size_t width,
+ size_t height,
+ size_t depth,
+ const uint8_t *input,
+ size_t inputRowPitch,
+ size_t inputDepthPitch,
+ uint8_t *output,
+ size_t outputRowPitch,
+ size_t outputDepthPitch,
+ bool punchthroughAlpha)
+{
+ for (size_t z = 0; z < depth; z++)
+ {
+ for (size_t y = 0; y < height; y += 4)
+ {
+ const ETC2Block *sourceRow =
+ OffsetDataPointer<ETC2Block>(input, y / 4, z, inputRowPitch, inputDepthPitch);
+ uint8_t *destRow =
+ OffsetDataPointer<uint8_t>(output, y, z, outputRowPitch, outputDepthPitch);
+
+ for (size_t x = 0; x < width; x += 4)
+ {
+ const ETC2Block *sourceBlock = sourceRow + (x / 4);
+ uint8_t *destPixels = destRow + (x * 4);
+
+ sourceBlock->decodeAsRGB(destPixels, x, y, width, height, outputRowPitch,
+ DefaultETCAlphaValues, punchthroughAlpha);
+ }
+ }
+ }
+}
+
+void LoadETC2RGB8ToBC1(size_t width,
+ size_t height,
+ size_t depth,
+ const uint8_t *input,
+ size_t inputRowPitch,
+ size_t inputDepthPitch,
+ uint8_t *output,
+ size_t outputRowPitch,
+ size_t outputDepthPitch,
+ bool punchthroughAlpha)
+{
+ for (size_t z = 0; z < depth; z++)
+ {
+ for (size_t y = 0; y < height; y += 4)
+ {
+ const ETC2Block *sourceRow =
+ OffsetDataPointer<ETC2Block>(input, y / 4, z, inputRowPitch, inputDepthPitch);
+ uint8_t *destRow =
+ OffsetDataPointer<uint8_t>(output, y / 4, z, outputRowPitch, outputDepthPitch);
+
+ for (size_t x = 0; x < width; x += 4)
+ {
+ const ETC2Block *sourceBlock = sourceRow + (x / 4);
+ uint8_t *destPixels = destRow + (x * 2);
+
+ sourceBlock->transcodeAsBC1(destPixels, x, y, width, height, DefaultETCAlphaValues,
+ punchthroughAlpha);
+ }
+ }
+ }
+}
+
+void LoadETC2RGBA8ToRGBA8(size_t width,
+ size_t height,
+ size_t depth,
+ const uint8_t *input,
+ size_t inputRowPitch,
+ size_t inputDepthPitch,
+ uint8_t *output,
+ size_t outputRowPitch,
+ size_t outputDepthPitch,
+ bool srgb)
+{
+ uint8_t decodedAlphaValues[4][4];
+
+ for (size_t z = 0; z < depth; z++)
+ {
+ for (size_t y = 0; y < height; y += 4)
+ {
+ const ETC2Block *sourceRow =
+ OffsetDataPointer<ETC2Block>(input, y / 4, z, inputRowPitch, inputDepthPitch);
+ uint8_t *destRow =
+ OffsetDataPointer<uint8_t>(output, y, z, outputRowPitch, outputDepthPitch);
+
+ for (size_t x = 0; x < width; x += 4)
+ {
+ const ETC2Block *sourceBlockAlpha = sourceRow + (x / 2);
+ sourceBlockAlpha->decodeAsSingleChannel(
+ reinterpret_cast<uint8_t *>(decodedAlphaValues), x, y, width, height, 1, 4,
+ false);
+
+ uint8_t *destPixels = destRow + (x * 4);
+ const ETC2Block *sourceBlockRGB = sourceBlockAlpha + 1;
+ sourceBlockRGB->decodeAsRGB(destPixels, x, y, width, height, outputRowPitch,
+ decodedAlphaValues, false);
+ }
+ }
+ }
+}
+
+} // anonymous namespace
+
+void LoadETC1RGB8ToRGBA8(size_t width,
+ size_t height,
+ size_t depth,
+ const uint8_t *input,
+ size_t inputRowPitch,
+ size_t inputDepthPitch,
+ uint8_t *output,
+ size_t outputRowPitch,
+ size_t outputDepthPitch)
+{
+ LoadETC2RGB8ToRGBA8(width, height, depth, input, inputRowPitch, inputDepthPitch, output,
+ outputRowPitch, outputDepthPitch, false);
+}
+
+void LoadETC1RGB8ToBC1(size_t width,
+ size_t height,
+ size_t depth,
+ const uint8_t *input,
+ size_t inputRowPitch,
+ size_t inputDepthPitch,
+ uint8_t *output,
+ size_t outputRowPitch,
+ size_t outputDepthPitch)
+{
+ LoadETC2RGB8ToBC1(width, height, depth, input, inputRowPitch, inputDepthPitch, output,
+ outputRowPitch, outputDepthPitch, false);
+}
+
+void LoadEACR11ToR8(size_t width,
+ size_t height,
+ size_t depth,
+ const uint8_t *input,
+ size_t inputRowPitch,
+ size_t inputDepthPitch,
+ uint8_t *output,
+ size_t outputRowPitch,
+ size_t outputDepthPitch)
+{
+ LoadR11EACToR8(width, height, depth, input, inputRowPitch, inputDepthPitch, output,
+ outputRowPitch, outputDepthPitch, false);
+}
+
+void LoadEACR11SToR8(size_t width,
+ size_t height,
+ size_t depth,
+ const uint8_t *input,
+ size_t inputRowPitch,
+ size_t inputDepthPitch,
+ uint8_t *output,
+ size_t outputRowPitch,
+ size_t outputDepthPitch)
+{
+ LoadR11EACToR8(width, height, depth, input, inputRowPitch, inputDepthPitch, output,
+ outputRowPitch, outputDepthPitch, true);
+}
+
+void LoadEACRG11ToRG8(size_t width,
+ size_t height,
+ size_t depth,
+ const uint8_t *input,
+ size_t inputRowPitch,
+ size_t inputDepthPitch,
+ uint8_t *output,
+ size_t outputRowPitch,
+ size_t outputDepthPitch)
+{
+ LoadRG11EACToRG8(width, height, depth, input, inputRowPitch, inputDepthPitch, output,
+ outputRowPitch, outputDepthPitch, false);
+}
+
+void LoadEACRG11SToRG8(size_t width,
+ size_t height,
+ size_t depth,
+ const uint8_t *input,
+ size_t inputRowPitch,
+ size_t inputDepthPitch,
+ uint8_t *output,
+ size_t outputRowPitch,
+ size_t outputDepthPitch)
+{
+ LoadRG11EACToRG8(width, height, depth, input, inputRowPitch, inputDepthPitch, output,
+ outputRowPitch, outputDepthPitch, true);
+}
+
+void LoadETC2RGB8ToRGBA8(size_t width,
+ size_t height,
+ size_t depth,
+ const uint8_t *input,
+ size_t inputRowPitch,
+ size_t inputDepthPitch,
+ uint8_t *output,
+ size_t outputRowPitch,
+ size_t outputDepthPitch)
+{
+ LoadETC2RGB8ToRGBA8(width, height, depth, input, inputRowPitch, inputDepthPitch, output,
+ outputRowPitch, outputDepthPitch, false);
+}
+
+void LoadETC2SRGB8ToRGBA8(size_t width,
+ size_t height,
+ size_t depth,
+ const uint8_t *input,
+ size_t inputRowPitch,
+ size_t inputDepthPitch,
+ uint8_t *output,
+ size_t outputRowPitch,
+ size_t outputDepthPitch)
+{
+ LoadETC2RGB8ToRGBA8(width, height, depth, input, inputRowPitch, inputDepthPitch, output,
+ outputRowPitch, outputDepthPitch, false);
+}
+
+void LoadETC2RGB8A1ToRGBA8(size_t width,
+ size_t height,
+ size_t depth,
+ const uint8_t *input,
+ size_t inputRowPitch,
+ size_t inputDepthPitch,
+ uint8_t *output,
+ size_t outputRowPitch,
+ size_t outputDepthPitch)
+{
+ LoadETC2RGB8ToRGBA8(width, height, depth, input, inputRowPitch, inputDepthPitch, output,
+ outputRowPitch, outputDepthPitch, true);
+}
+
+void LoadETC2SRGB8A1ToRGBA8(size_t width,
+ size_t height,
+ size_t depth,
+ const uint8_t *input,
+ size_t inputRowPitch,
+ size_t inputDepthPitch,
+ uint8_t *output,
+ size_t outputRowPitch,
+ size_t outputDepthPitch)
+{
+ LoadETC2RGB8ToRGBA8(width, height, depth, input, inputRowPitch, inputDepthPitch, output,
+ outputRowPitch, outputDepthPitch, true);
+}
+
+void LoadETC2RGBA8ToRGBA8(size_t width,
+ size_t height,
+ size_t depth,
+ const uint8_t *input,
+ size_t inputRowPitch,
+ size_t inputDepthPitch,
+ uint8_t *output,
+ size_t outputRowPitch,
+ size_t outputDepthPitch)
+{
+ LoadETC2RGBA8ToRGBA8(width, height, depth, input, inputRowPitch, inputDepthPitch, output,
+ outputRowPitch, outputDepthPitch, false);
+}
+
+void LoadETC2SRGBA8ToSRGBA8(size_t width,
+ size_t height,
+ size_t depth,
+ const uint8_t *input,
+ size_t inputRowPitch,
+ size_t inputDepthPitch,
+ uint8_t *output,
+ size_t outputRowPitch,
+ size_t outputDepthPitch)
+{
+ LoadETC2RGBA8ToRGBA8(width, height, depth, input, inputRowPitch, inputDepthPitch, output,
+ outputRowPitch, outputDepthPitch, true);
+}
+
+} // namespace rx
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimage_etc.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimage_etc.h
new file mode 100644
index 0000000000..dc64e0461b
--- /dev/null
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimage_etc.h
@@ -0,0 +1,140 @@
+//
+// Copyright (c) 2013-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.
+//
+
+// loadimage_etc.h: Decodes ETC and EAC encoded textures.
+
+#ifndef LIBANGLE_RENDERER_D3D_LOADIMAGE_ETC_H_
+#define LIBANGLE_RENDERER_D3D_LOADIMAGE_ETC_H_
+
+#include "libANGLE/angletypes.h"
+
+#include <stdint.h>
+
+namespace rx
+{
+
+void LoadETC1RGB8ToRGBA8(size_t width,
+ size_t height,
+ size_t depth,
+ const uint8_t *input,
+ size_t inputRowPitch,
+ size_t inputDepthPitch,
+ uint8_t *output,
+ size_t outputRowPitch,
+ size_t outputDepthPitch);
+
+void LoadETC1RGB8ToBC1(size_t width,
+ size_t height,
+ size_t depth,
+ const uint8_t *input,
+ size_t inputRowPitch,
+ size_t inputDepthPitch,
+ uint8_t *output,
+ size_t outputRowPitch,
+ size_t outputDepthPitch);
+
+void LoadEACR11ToR8(size_t width,
+ size_t height,
+ size_t depth,
+ const uint8_t *input,
+ size_t inputRowPitch,
+ size_t inputDepthPitch,
+ uint8_t *output,
+ size_t outputRowPitch,
+ size_t outputDepthPitch);
+
+void LoadEACR11SToR8(size_t width,
+ size_t height,
+ size_t depth,
+ const uint8_t *input,
+ size_t inputRowPitch,
+ size_t inputDepthPitch,
+ uint8_t *output,
+ size_t outputRowPitch,
+ size_t outputDepthPitch);
+
+void LoadEACRG11ToRG8(size_t width,
+ size_t height,
+ size_t depth,
+ const uint8_t *input,
+ size_t inputRowPitch,
+ size_t inputDepthPitch,
+ uint8_t *output,
+ size_t outputRowPitch,
+ size_t outputDepthPitch);
+
+void LoadEACRG11SToRG8(size_t width,
+ size_t height,
+ size_t depth,
+ const uint8_t *input,
+ size_t inputRowPitch,
+ size_t inputDepthPitch,
+ uint8_t *output,
+ size_t outputRowPitch,
+ size_t outputDepthPitch);
+
+void LoadETC2RGB8ToRGBA8(size_t width,
+ size_t height,
+ size_t depth,
+ const uint8_t *input,
+ size_t inputRowPitch,
+ size_t inputDepthPitch,
+ uint8_t *output,
+ size_t outputRowPitch,
+ size_t outputDepthPitch);
+
+void LoadETC2SRGB8ToRGBA8(size_t width,
+ size_t height,
+ size_t depth,
+ const uint8_t *input,
+ size_t inputRowPitch,
+ size_t inputDepthPitch,
+ uint8_t *output,
+ size_t outputRowPitch,
+ size_t outputDepthPitch);
+
+void LoadETC2RGB8A1ToRGBA8(size_t width,
+ size_t height,
+ size_t depth,
+ const uint8_t *input,
+ size_t inputRowPitch,
+ size_t inputDepthPitch,
+ uint8_t *output,
+ size_t outputRowPitch,
+ size_t outputDepthPitch);
+
+void LoadETC2SRGB8A1ToRGBA8(size_t width,
+ size_t height,
+ size_t depth,
+ const uint8_t *input,
+ size_t inputRowPitch,
+ size_t inputDepthPitch,
+ uint8_t *output,
+ size_t outputRowPitch,
+ size_t outputDepthPitch);
+
+void LoadETC2RGBA8ToRGBA8(size_t width,
+ size_t height,
+ size_t depth,
+ const uint8_t *input,
+ size_t inputRowPitch,
+ size_t inputDepthPitch,
+ uint8_t *output,
+ size_t outputRowPitch,
+ size_t outputDepthPitch);
+
+void LoadETC2SRGBA8ToSRGBA8(size_t width,
+ size_t height,
+ size_t depth,
+ const uint8_t *input,
+ size_t inputRowPitch,
+ size_t inputDepthPitch,
+ uint8_t *output,
+ size_t outputRowPitch,
+ size_t outputDepthPitch);
+}
+
+#endif // LIBANGLE_RENDERER_D3D_LOADIMAGE_ETC_H_
diff --git a/src/3rdparty/angle/src/libANGLE/validationEGL.cpp b/src/3rdparty/angle/src/libANGLE/validationEGL.cpp
index 12ee6a2b93..972f6a7a5a 100644
--- a/src/3rdparty/angle/src/libANGLE/validationEGL.cpp
+++ b/src/3rdparty/angle/src/libANGLE/validationEGL.cpp
@@ -8,13 +8,87 @@
#include "libANGLE/validationEGL.h"
+#include "common/utilities.h"
#include "libANGLE/Config.h"
#include "libANGLE/Context.h"
+#include "libANGLE/Device.h"
#include "libANGLE/Display.h"
+#include "libANGLE/Image.h"
#include "libANGLE/Surface.h"
#include <EGL/eglext.h>
+namespace
+{
+size_t GetMaximumMipLevel(const gl::Context *context, GLenum target)
+{
+ const gl::Caps &caps = context->getCaps();
+
+ size_t maxDimension = 0;
+ switch (target)
+ {
+ case GL_TEXTURE_2D:
+ maxDimension = caps.max2DTextureSize;
+ break;
+ case GL_TEXTURE_CUBE_MAP:
+ maxDimension = caps.maxCubeMapTextureSize;
+ break;
+ case GL_TEXTURE_3D:
+ maxDimension = caps.max3DTextureSize;
+ break;
+ case GL_TEXTURE_2D_ARRAY:
+ maxDimension = caps.max2DTextureSize;
+ break;
+ default:
+ UNREACHABLE();
+ }
+
+ return gl::log2(static_cast<int>(maxDimension));
+}
+
+bool TextureHasNonZeroMipLevelsSpecified(const gl::Context *context, const gl::Texture *texture)
+{
+ size_t maxMip = GetMaximumMipLevel(context, texture->getTarget());
+ for (size_t level = 1; level < maxMip; level++)
+ {
+ if (texture->getTarget() == GL_TEXTURE_CUBE_MAP)
+ {
+ for (GLenum face = gl::FirstCubeMapTextureTarget; face <= gl::LastCubeMapTextureTarget;
+ face++)
+ {
+ if (texture->getInternalFormat(face, level) != GL_NONE)
+ {
+ return true;
+ }
+ }
+ }
+ else
+ {
+ if (texture->getInternalFormat(texture->getTarget(), level) != GL_NONE)
+ {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool CubeTextureHasUnspecifiedLevel0Face(const gl::Texture *texture)
+{
+ ASSERT(texture->getTarget() == GL_TEXTURE_CUBE_MAP);
+ for (GLenum face = gl::FirstCubeMapTextureTarget; face <= gl::LastCubeMapTextureTarget; face++)
+ {
+ if (texture->getInternalFormat(face, 0) == GL_NONE)
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+}
+
namespace egl
{
@@ -22,12 +96,17 @@ Error ValidateDisplay(const Display *display)
{
if (display == EGL_NO_DISPLAY)
{
- return Error(EGL_BAD_DISPLAY);
+ return Error(EGL_BAD_DISPLAY, "display is EGL_NO_DISPLAY.");
+ }
+
+ if (!Display::isValidDisplay(display))
+ {
+ return Error(EGL_BAD_DISPLAY, "display is not a valid display.");
}
if (!display->isInitialized())
{
- return Error(EGL_NOT_INITIALIZED);
+ return Error(EGL_NOT_INITIALIZED, "display is not initialized.");
}
return Error(EGL_SUCCESS);
@@ -81,6 +160,22 @@ Error ValidateContext(const Display *display, gl::Context *context)
return Error(EGL_SUCCESS);
}
+Error ValidateImage(const Display *display, const Image *image)
+{
+ Error error = ValidateDisplay(display);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ if (!display->isValidImage(image))
+ {
+ return Error(EGL_BAD_PARAMETER, "image is not valid.");
+ }
+
+ return Error(EGL_SUCCESS);
+}
+
Error ValidateCreateContext(Display *display, Config *configuration, gl::Context *shareContext,
const AttributeMap& attributes)
{
@@ -115,6 +210,9 @@ Error ValidateCreateContext(Display *display, Config *configuration, gl::Context
contextFlags = value;
break;
+ case EGL_CONTEXT_OPENGL_DEBUG:
+ break;
+
case EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR:
// Only valid for OpenGL (non-ES) contexts
return Error(EGL_BAD_ATTRIBUTE);
@@ -150,6 +248,17 @@ Error ValidateCreateContext(Display *display, Config *configuration, gl::Context
}
break;
+ case EGL_CONTEXT_OPENGL_NO_ERROR_KHR:
+ if (!display->getExtensions().createContextNoError)
+ {
+ return Error(EGL_BAD_ATTRIBUTE, "Invalid Context attribute.");
+ }
+ if (value != EGL_TRUE && value != EGL_FALSE)
+ {
+ return Error(EGL_BAD_ATTRIBUTE, "Attribute must be EGL_TRUE or EGL_FALSE.");
+ }
+ break;
+
default:
return Error(EGL_BAD_ATTRIBUTE);
}
@@ -248,6 +357,13 @@ Error ValidateCreateWindowSurface(Display *display, Config *config, EGLNativeWin
}
break;
+ case EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE:
+ if (!displayExtensions.flexibleSurfaceCompatibility)
+ {
+ return Error(EGL_BAD_ATTRIBUTE);
+ }
+ break;
+
case EGL_WIDTH:
case EGL_HEIGHT:
if (!displayExtensions.windowFixedSize)
@@ -267,12 +383,26 @@ Error ValidateCreateWindowSurface(Display *display, Config *config, EGLNativeWin
}
break;
+ case EGL_SURFACE_ORIENTATION_ANGLE:
+ if (!displayExtensions.surfaceOrientation)
+ {
+ return Error(EGL_BAD_ATTRIBUTE, "EGL_ANGLE_surface_orientation is not enabled.");
+ }
+ break;
+
case EGL_VG_COLORSPACE:
return Error(EGL_BAD_MATCH);
case EGL_VG_ALPHA_FORMAT:
return Error(EGL_BAD_MATCH);
+ case EGL_DIRECT_COMPOSITION_ANGLE:
+ if (!displayExtensions.directComposition)
+ {
+ return Error(EGL_BAD_ATTRIBUTE);
+ }
+ break;
+
default:
return Error(EGL_BAD_ATTRIBUTE);
}
@@ -293,7 +423,9 @@ Error ValidateCreatePbufferSurface(Display *display, Config *config, const Attri
{
return error;
}
-
+
+ const DisplayExtensions &displayExtensions = display->getExtensions();
+
for (AttributeMap::const_iterator attributeIter = attributes.begin(); attributeIter != attributes.end(); attributeIter++)
{
EGLint attribute = attributeIter->first;
@@ -344,6 +476,16 @@ Error ValidateCreatePbufferSurface(Display *display, Config *config, const Attri
case EGL_VG_ALPHA_FORMAT:
break;
+ case EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE:
+ if (!displayExtensions.flexibleSurfaceCompatibility)
+ {
+ return Error(
+ EGL_BAD_ATTRIBUTE,
+ "EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE cannot be used without "
+ "EGL_ANGLE_flexible_surface_compatibility support.");
+ }
+ break;
+
default:
return Error(EGL_BAD_ATTRIBUTE);
}
@@ -354,6 +496,7 @@ Error ValidateCreatePbufferSurface(Display *display, Config *config, const Attri
return Error(EGL_BAD_MATCH);
}
+#if !defined(ANGLE_ENABLE_WINDOWS_STORE) // On Windows Store, we know the originating texture came from D3D11, so bypass this check
const Caps &caps = display->getCaps();
EGLenum textureFormat = attributes.get(EGL_TEXTURE_FORMAT, EGL_NO_TEXTURE);
@@ -377,6 +520,7 @@ Error ValidateCreatePbufferSurface(Display *display, Config *config, const Attri
{
return Error(EGL_BAD_MATCH);
}
+#endif
return Error(EGL_SUCCESS);
}
@@ -454,6 +598,16 @@ Error ValidateCreatePbufferFromClientBuffer(Display *display, EGLenum buftype, E
case EGL_MIPMAP_TEXTURE:
break;
+ case EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE:
+ if (!displayExtensions.flexibleSurfaceCompatibility)
+ {
+ return Error(
+ EGL_BAD_ATTRIBUTE,
+ "EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE cannot be used without "
+ "EGL_ANGLE_flexible_surface_compatibility support.");
+ }
+ break;
+
default:
return Error(EGL_BAD_ATTRIBUTE);
}
@@ -488,16 +642,418 @@ Error ValidateCreatePbufferFromClientBuffer(Display *display, EGLenum buftype, E
return Error(EGL_BAD_ATTRIBUTE);
}
-#if !defined(ANGLE_ENABLE_WINDOWS_STORE) // On Windows Store, we know the originating texture came from D3D11, so bypass this check
const Caps &caps = display->getCaps();
if (textureFormat != EGL_NO_TEXTURE && !caps.textureNPOT && (!gl::isPow2(width) || !gl::isPow2(height)))
{
return Error(EGL_BAD_MATCH);
}
-#endif
}
return Error(EGL_SUCCESS);
}
+Error ValidateCompatibleConfigs(const Display *display,
+ const Config *config1,
+ const Surface *surface,
+ const Config *config2,
+ EGLint surfaceType)
+{
+
+ if (!surface->flexibleSurfaceCompatibilityRequested())
+ {
+ // Config compatibility is defined in section 2.2 of the EGL 1.5 spec
+
+ bool colorBufferCompat = config1->colorBufferType == config2->colorBufferType;
+ if (!colorBufferCompat)
+ {
+ return Error(EGL_BAD_MATCH, "Color buffer types are not compatible.");
+ }
+
+ bool colorCompat =
+ config1->redSize == config2->redSize && config1->greenSize == config2->greenSize &&
+ config1->blueSize == config2->blueSize && config1->alphaSize == config2->alphaSize &&
+ config1->luminanceSize == config2->luminanceSize;
+ if (!colorCompat)
+ {
+ return Error(EGL_BAD_MATCH, "Color buffer sizes are not compatible.");
+ }
+
+ bool dsCompat = config1->depthSize == config2->depthSize &&
+ config1->stencilSize == config2->stencilSize;
+ if (!dsCompat)
+ {
+ return Error(EGL_BAD_MATCH, "Depth-stencil buffer types are not compatible.");
+ }
+ }
+
+ bool surfaceTypeCompat = (config1->surfaceType & config2->surfaceType & surfaceType) != 0;
+ if (!surfaceTypeCompat)
+ {
+ return Error(EGL_BAD_MATCH, "Surface types are not compatible.");
+ }
+
+ return Error(EGL_SUCCESS);
+}
+
+Error ValidateCreateImageKHR(const Display *display,
+ gl::Context *context,
+ EGLenum target,
+ EGLClientBuffer buffer,
+ const AttributeMap &attributes)
+{
+ Error error = ValidateContext(display, context);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ const DisplayExtensions &displayExtensions = display->getExtensions();
+
+ if (!displayExtensions.imageBase && !displayExtensions.image)
+ {
+ // It is out of spec what happens when calling an extension function when the extension is
+ // not available.
+ // EGL_BAD_DISPLAY seems like a reasonable error.
+ return Error(EGL_BAD_DISPLAY, "EGL_KHR_image not supported.");
+ }
+
+ // TODO(geofflang): Complete validation from EGL_KHR_image_base:
+ // If the resource specified by <dpy>, <ctx>, <target>, <buffer> and <attrib_list> is itself an
+ // EGLImage sibling, the error EGL_BAD_ACCESS is generated.
+
+ for (AttributeMap::const_iterator attributeIter = attributes.begin();
+ attributeIter != attributes.end(); attributeIter++)
+ {
+ EGLint attribute = attributeIter->first;
+ EGLint value = attributeIter->second;
+
+ switch (attribute)
+ {
+ case EGL_IMAGE_PRESERVED_KHR:
+ switch (value)
+ {
+ case EGL_TRUE:
+ case EGL_FALSE:
+ break;
+
+ default:
+ return Error(EGL_BAD_PARAMETER,
+ "EGL_IMAGE_PRESERVED_KHR must be EGL_TRUE or EGL_FALSE.");
+ }
+ break;
+
+ case EGL_GL_TEXTURE_LEVEL_KHR:
+ if (!displayExtensions.glTexture2DImage &&
+ !displayExtensions.glTextureCubemapImage && !displayExtensions.glTexture3DImage)
+ {
+ return Error(EGL_BAD_PARAMETER,
+ "EGL_GL_TEXTURE_LEVEL_KHR cannot be used without "
+ "KHR_gl_texture_*_image support.");
+ }
+
+ if (value < 0)
+ {
+ return Error(EGL_BAD_PARAMETER, "EGL_GL_TEXTURE_LEVEL_KHR cannot be negative.");
+ }
+ break;
+
+ case EGL_GL_TEXTURE_ZOFFSET_KHR:
+ if (!displayExtensions.glTexture3DImage)
+ {
+ return Error(EGL_BAD_PARAMETER,
+ "EGL_GL_TEXTURE_ZOFFSET_KHR cannot be used without "
+ "KHR_gl_texture_3D_image support.");
+ }
+ break;
+
+ default:
+ return Error(EGL_BAD_PARAMETER, "invalid attribute: 0x%X", attribute);
+ }
+ }
+
+ switch (target)
+ {
+ case EGL_GL_TEXTURE_2D_KHR:
+ {
+ if (!displayExtensions.glTexture2DImage)
+ {
+ return Error(EGL_BAD_PARAMETER, "KHR_gl_texture_2D_image not supported.");
+ }
+
+ if (buffer == 0)
+ {
+ return Error(EGL_BAD_PARAMETER,
+ "buffer cannot reference a 2D texture with the name 0.");
+ }
+
+ const gl::Texture *texture =
+ context->getTexture(egl_gl::EGLClientBufferToGLObjectHandle(buffer));
+ if (texture == nullptr || texture->getTarget() != GL_TEXTURE_2D)
+ {
+ return Error(EGL_BAD_PARAMETER, "target is not a 2D texture.");
+ }
+
+ if (texture->getBoundSurface() != nullptr)
+ {
+ return Error(EGL_BAD_ACCESS, "texture has a surface bound to it.");
+ }
+
+ EGLint level = attributes.get(EGL_GL_TEXTURE_LEVEL_KHR, 0);
+ if (texture->getWidth(GL_TEXTURE_2D, static_cast<size_t>(level)) == 0 ||
+ texture->getHeight(GL_TEXTURE_2D, static_cast<size_t>(level)) == 0)
+ {
+ return Error(EGL_BAD_PARAMETER,
+ "target 2D texture does not have a valid size at specified level.");
+ }
+
+ if (level > 0 && (!texture->isMipmapComplete() ||
+ static_cast<size_t>(level) >= texture->getMipCompleteLevels()))
+ {
+ return Error(EGL_BAD_PARAMETER, "texture must be complete if level is non-zero.");
+ }
+
+ if (level == 0 && !texture->isMipmapComplete() &&
+ TextureHasNonZeroMipLevelsSpecified(context, texture))
+ {
+ return Error(EGL_BAD_PARAMETER,
+ "if level is zero and the texture is incomplete, it must have no mip "
+ "levels specified except zero.");
+ }
+ }
+ break;
+
+ 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:
+ {
+ if (!displayExtensions.glTextureCubemapImage)
+ {
+ return Error(EGL_BAD_PARAMETER, "KHR_gl_texture_cubemap_image not supported.");
+ }
+
+ if (buffer == 0)
+ {
+ return Error(EGL_BAD_PARAMETER,
+ "buffer cannot reference a cubemap texture with the name 0.");
+ }
+
+ const gl::Texture *texture =
+ context->getTexture(egl_gl::EGLClientBufferToGLObjectHandle(buffer));
+ if (texture == nullptr || texture->getTarget() != GL_TEXTURE_CUBE_MAP)
+ {
+ return Error(EGL_BAD_PARAMETER, "target is not a cubemap texture.");
+ }
+
+ if (texture->getBoundSurface() != nullptr)
+ {
+ return Error(EGL_BAD_ACCESS, "texture has a surface bound to it.");
+ }
+
+ EGLint level = attributes.get(EGL_GL_TEXTURE_LEVEL_KHR, 0);
+ GLenum cubeMapFace = egl_gl::EGLCubeMapTargetToGLCubeMapTarget(target);
+ if (texture->getWidth(cubeMapFace, static_cast<size_t>(level)) == 0 ||
+ texture->getHeight(cubeMapFace, static_cast<size_t>(level)) == 0)
+ {
+ return Error(EGL_BAD_PARAMETER,
+ "target cubemap texture does not have a valid size at specified level "
+ "and face.");
+ }
+
+ if (level > 0 && (!texture->isMipmapComplete() ||
+ static_cast<size_t>(level) >= texture->getMipCompleteLevels()))
+ {
+ return Error(EGL_BAD_PARAMETER, "texture must be complete if level is non-zero.");
+ }
+
+ if (level == 0 && !texture->isMipmapComplete() &&
+ TextureHasNonZeroMipLevelsSpecified(context, texture))
+ {
+ return Error(EGL_BAD_PARAMETER,
+ "if level is zero and the texture is incomplete, it must have no mip "
+ "levels specified except zero.");
+ }
+
+ if (level == 0 && !texture->isMipmapComplete() &&
+ CubeTextureHasUnspecifiedLevel0Face(texture))
+ {
+ return Error(EGL_BAD_PARAMETER,
+ "if level is zero and the texture is incomplete, it must have all of "
+ "its faces specified at level zero.");
+ }
+ }
+ break;
+
+ case EGL_GL_TEXTURE_3D_KHR:
+ {
+ if (!displayExtensions.glTexture3DImage)
+ {
+ return Error(EGL_BAD_PARAMETER, "KHR_gl_texture_3D_image not supported.");
+ }
+
+ if (buffer == 0)
+ {
+ return Error(EGL_BAD_PARAMETER,
+ "buffer cannot reference a 3D texture with the name 0.");
+ }
+
+ const gl::Texture *texture =
+ context->getTexture(egl_gl::EGLClientBufferToGLObjectHandle(buffer));
+ if (texture == nullptr || texture->getTarget() != GL_TEXTURE_3D)
+ {
+ return Error(EGL_BAD_PARAMETER, "target is not a 3D texture.");
+ }
+
+ if (texture->getBoundSurface() != nullptr)
+ {
+ return Error(EGL_BAD_ACCESS, "texture has a surface bound to it.");
+ }
+
+ EGLint level = attributes.get(EGL_GL_TEXTURE_LEVEL_KHR, 0);
+ EGLint zOffset = attributes.get(EGL_GL_TEXTURE_ZOFFSET_KHR, 0);
+ if (texture->getWidth(GL_TEXTURE_3D, static_cast<size_t>(level)) == 0 ||
+ texture->getHeight(GL_TEXTURE_3D, static_cast<size_t>(level)) == 0 ||
+ texture->getDepth(GL_TEXTURE_3D, static_cast<size_t>(level)) == 0)
+ {
+ return Error(EGL_BAD_PARAMETER,
+ "target 3D texture does not have a valid size at specified level.");
+ }
+
+ if (static_cast<size_t>(zOffset) >=
+ texture->getDepth(GL_TEXTURE_3D, static_cast<size_t>(level)))
+ {
+ return Error(EGL_BAD_PARAMETER,
+ "target 3D texture does not have enough layers for the specified Z "
+ "offset at the specified level.");
+ }
+
+ if (level > 0 && (!texture->isMipmapComplete() ||
+ static_cast<size_t>(level) >= texture->getMipCompleteLevels()))
+ {
+ return Error(EGL_BAD_PARAMETER, "texture must be complete if level is non-zero.");
+ }
+
+ if (level == 0 && !texture->isMipmapComplete() &&
+ TextureHasNonZeroMipLevelsSpecified(context, texture))
+ {
+ return Error(EGL_BAD_PARAMETER,
+ "if level is zero and the texture is incomplete, it must have no mip "
+ "levels specified except zero.");
+ }
+ }
+ break;
+
+ case EGL_GL_RENDERBUFFER_KHR:
+ {
+ if (!displayExtensions.glRenderbufferImage)
+ {
+ return Error(EGL_BAD_PARAMETER, "KHR_gl_renderbuffer_image not supported.");
+ }
+
+ if (attributes.contains(EGL_GL_TEXTURE_LEVEL_KHR))
+ {
+ return Error(EGL_BAD_PARAMETER,
+ "EGL_GL_TEXTURE_LEVEL_KHR cannot be used in conjunction with a "
+ "renderbuffer target.");
+ }
+
+ if (buffer == 0)
+ {
+ return Error(EGL_BAD_PARAMETER,
+ "buffer cannot reference a renderbuffer with the name 0.");
+ }
+
+ const gl::Renderbuffer *renderbuffer =
+ context->getRenderbuffer(egl_gl::EGLClientBufferToGLObjectHandle(buffer));
+ if (renderbuffer == nullptr)
+ {
+ return Error(EGL_BAD_PARAMETER, "target is not a renderbuffer.");
+ }
+
+ if (renderbuffer->getSamples() > 0)
+ {
+ return Error(EGL_BAD_PARAMETER, "target renderbuffer cannot be multisampled.");
+ }
+ }
+ break;
+
+ default:
+ return Error(EGL_BAD_PARAMETER, "invalid target: 0x%X", target);
+ }
+
+ return Error(EGL_SUCCESS);
+}
+
+Error ValidateDestroyImageKHR(const Display *display, const Image *image)
+{
+ Error error = ValidateImage(display, image);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ if (!display->getExtensions().imageBase && !display->getExtensions().image)
+ {
+ // It is out of spec what happens when calling an extension function when the extension is
+ // not available.
+ // EGL_BAD_DISPLAY seems like a reasonable error.
+ return Error(EGL_BAD_DISPLAY);
+ }
+
+ return Error(EGL_SUCCESS);
+}
+
+Error ValidateCreateDeviceANGLE(EGLint device_type,
+ void *native_device,
+ const EGLAttrib *attrib_list)
+{
+ const ClientExtensions &clientExtensions = Display::getClientExtensions();
+ if (!clientExtensions.deviceCreation)
+ {
+ return Error(EGL_BAD_ACCESS, "Device creation extension not active");
+ }
+
+ if (attrib_list != nullptr && attrib_list[0] != EGL_NONE)
+ {
+ return Error(EGL_BAD_ATTRIBUTE, "Invalid attrib_list parameter");
+ }
+
+ switch (device_type)
+ {
+ case EGL_D3D11_DEVICE_ANGLE:
+ if (!clientExtensions.deviceCreationD3D11)
+ {
+ return Error(EGL_BAD_ATTRIBUTE, "D3D11 device creation extension not active");
+ }
+ break;
+ default:
+ return Error(EGL_BAD_ATTRIBUTE, "Invalid device_type parameter");
+ }
+
+ return Error(EGL_SUCCESS);
+}
+
+Error ValidateReleaseDeviceANGLE(Device *device)
+{
+ const ClientExtensions &clientExtensions = Display::getClientExtensions();
+ if (!clientExtensions.deviceCreation)
+ {
+ return Error(EGL_BAD_ACCESS, "Device creation extension not active");
+ }
+
+ if (device == EGL_NO_DEVICE_EXT || !Device::IsValidDevice(device))
+ {
+ return Error(EGL_BAD_DEVICE_EXT, "Invalid device parameter");
+ }
+
+ Display *owningDisplay = device->getOwningDisplay();
+ if (owningDisplay != nullptr)
+ {
+ return Error(EGL_BAD_DEVICE_EXT, "Device must have been created using eglCreateDevice");
+ }
+
+ return Error(EGL_SUCCESS);
+}
}
diff --git a/src/3rdparty/angle/src/libANGLE/validationEGL.h b/src/3rdparty/angle/src/libANGLE/validationEGL.h
index 4daff791fd..eaafddc20d 100644
--- a/src/3rdparty/angle/src/libANGLE/validationEGL.h
+++ b/src/3rdparty/angle/src/libANGLE/validationEGL.h
@@ -23,7 +23,9 @@ namespace egl
class AttributeMap;
struct Config;
+class Device;
class Display;
+class Image;
class Surface;
// Object validation
@@ -31,6 +33,7 @@ Error ValidateDisplay(const Display *display);
Error ValidateSurface(const Display *display, Surface *surface);
Error ValidateConfig(const Display *display, const Config *config);
Error ValidateContext(const Display *display, gl::Context *context);
+Error ValidateImage(const Display *display, const Image *image);
// Entry point validation
Error ValidateCreateContext(Display *display, Config *configuration, gl::Context *shareContext,
@@ -43,7 +46,24 @@ Error ValidateCreatePbufferSurface(Display *display, Config *config, const Attri
Error ValidateCreatePbufferFromClientBuffer(Display *display, EGLenum buftype, EGLClientBuffer buffer,
Config *config, const AttributeMap& attributes);
+Error ValidateCreateImageKHR(const Display *display,
+ gl::Context *context,
+ EGLenum target,
+ EGLClientBuffer buffer,
+ const AttributeMap &attributes);
+Error ValidateDestroyImageKHR(const Display *display, const Image *image);
+Error ValidateCreateDeviceANGLE(EGLint device_type,
+ void *native_device,
+ const EGLAttrib *attrib_list);
+Error ValidateReleaseDeviceANGLE(Device *device);
+
+// Other validation
+Error ValidateCompatibleConfigs(const Display *display,
+ const Config *config1,
+ const Surface *surface,
+ const Config *config2,
+ EGLint surfaceType);
}
#endif // LIBANGLE_VALIDATIONEGL_H_
diff --git a/src/3rdparty/angle/src/libANGLE/validationES.cpp b/src/3rdparty/angle/src/libANGLE/validationES.cpp
index d267cbf2e6..12c76120bd 100644
--- a/src/3rdparty/angle/src/libANGLE/validationES.cpp
+++ b/src/3rdparty/angle/src/libANGLE/validationES.cpp
@@ -10,22 +10,90 @@
#include "libANGLE/validationES2.h"
#include "libANGLE/validationES3.h"
#include "libANGLE/Context.h"
+#include "libANGLE/Display.h"
#include "libANGLE/Texture.h"
#include "libANGLE/Framebuffer.h"
#include "libANGLE/FramebufferAttachment.h"
#include "libANGLE/formatutils.h"
+#include "libANGLE/Image.h"
#include "libANGLE/Query.h"
#include "libANGLE/Program.h"
#include "libANGLE/Uniform.h"
#include "libANGLE/TransformFeedback.h"
#include "libANGLE/VertexArray.h"
-#include "libANGLE/renderer/BufferImpl.h"
#include "common/mathutil.h"
#include "common/utilities.h"
namespace gl
{
+const char *g_ExceedsMaxElementErrorMessage = "Element value exceeds maximum element index.";
+
+namespace
+{
+bool ValidateDrawAttribs(ValidationContext *context, GLint primcount, GLint maxVertex)
+{
+ const gl::State &state = context->getState();
+ const gl::Program *program = state.getProgram();
+
+ const VertexArray *vao = state.getVertexArray();
+ const auto &vertexAttribs = vao->getVertexAttributes();
+ size_t maxEnabledAttrib = vao->getMaxEnabledAttribute();
+ for (size_t attributeIndex = 0; attributeIndex < maxEnabledAttrib; ++attributeIndex)
+ {
+ const VertexAttribute &attrib = vertexAttribs[attributeIndex];
+ if (program->isAttribLocationActive(attributeIndex) && attrib.enabled)
+ {
+ gl::Buffer *buffer = attrib.buffer.get();
+
+ if (buffer)
+ {
+ GLint64 attribStride = static_cast<GLint64>(ComputeVertexAttributeStride(attrib));
+ GLint64 maxVertexElement = 0;
+
+ if (attrib.divisor > 0)
+ {
+ maxVertexElement =
+ static_cast<GLint64>(primcount) / static_cast<GLint64>(attrib.divisor);
+ }
+ else
+ {
+ maxVertexElement = static_cast<GLint64>(maxVertex);
+ }
+
+ // If we're drawing zero vertices, we have enough data.
+ if (maxVertexElement > 0)
+ {
+ // Note: Last vertex element does not take the full stride!
+ GLint64 attribSize =
+ static_cast<GLint64>(ComputeVertexAttributeTypeSize(attrib));
+ GLint64 attribDataSize = (maxVertexElement - 1) * attribStride + attribSize;
+
+ // [OpenGL ES 3.0.2] section 2.9.4 page 40:
+ // We can return INVALID_OPERATION if our vertex attribute does not have
+ // enough backing data.
+ if (attribDataSize > buffer->getSize())
+ {
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
+ }
+ }
+ }
+ else if (attrib.pointer == NULL)
+ {
+ // This is an application error that would normally result in a crash,
+ // but we catch it and return an error
+ context->recordError(Error(
+ GL_INVALID_OPERATION, "An enabled vertex array has no buffer and no pointer."));
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+} // anonymous namespace
bool ValidCap(const Context *context, GLenum cap)
{
@@ -41,15 +109,21 @@ bool ValidCap(const Context *context, GLenum cap)
case GL_BLEND:
case GL_DITHER:
return true;
+
case GL_PRIMITIVE_RESTART_FIXED_INDEX:
case GL_RASTERIZER_DISCARD:
return (context->getClientVersion() >= 3);
+
+ case GL_DEBUG_OUTPUT_SYNCHRONOUS:
+ case GL_DEBUG_OUTPUT:
+ return context->getExtensions().debug;
+
default:
return false;
}
}
-bool ValidTextureTarget(const Context *context, GLenum target)
+bool ValidTextureTarget(const ValidationContext *context, GLenum target)
{
switch (target)
{
@@ -66,11 +140,37 @@ bool ValidTextureTarget(const Context *context, GLenum target)
}
}
+bool ValidTexture2DTarget(const ValidationContext *context, GLenum target)
+{
+ switch (target)
+ {
+ case GL_TEXTURE_2D:
+ case GL_TEXTURE_CUBE_MAP:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+bool ValidTexture3DTarget(const ValidationContext *context, GLenum target)
+{
+ switch (target)
+ {
+ case GL_TEXTURE_3D:
+ case GL_TEXTURE_2D_ARRAY:
+ return (context->getClientVersion() >= 3);
+
+ default:
+ return false;
+ }
+}
+
// This function differs from ValidTextureTarget in that the target must be
// usable as the destination of a 2D operation-- so a cube face is valid, but
// GL_TEXTURE_CUBE_MAP is not.
// Note: duplicate of IsInternalTextureTarget
-bool ValidTexture2DDestinationTarget(const Context *context, GLenum target)
+bool ValidTexture2DDestinationTarget(const ValidationContext *context, GLenum target)
{
switch (target)
{
@@ -82,9 +182,18 @@ bool ValidTexture2DDestinationTarget(const Context *context, GLenum target)
case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
return true;
- case GL_TEXTURE_2D_ARRAY:
+ default:
+ return false;
+ }
+}
+
+bool ValidTexture3DDestinationTarget(const ValidationContext *context, GLenum target)
+{
+ switch (target)
+ {
case GL_TEXTURE_3D:
- return (context->getClientVersion() >= 3);
+ case GL_TEXTURE_2D_ARRAY:
+ return true;
default:
return false;
}
@@ -114,7 +223,7 @@ bool ValidBufferTarget(const Context *context, GLenum target)
case GL_PIXEL_PACK_BUFFER:
case GL_PIXEL_UNPACK_BUFFER:
- return context->getExtensions().pixelBufferObject;
+ return (context->getExtensions().pixelBufferObject || context->getClientVersion() >= 3);
case GL_COPY_READ_BUFFER:
case GL_COPY_WRITE_BUFFER:
@@ -129,55 +238,79 @@ bool ValidBufferTarget(const Context *context, GLenum target)
bool ValidBufferParameter(const Context *context, GLenum pname)
{
+ const Extensions &extensions = context->getExtensions();
+
switch (pname)
{
case GL_BUFFER_USAGE:
case GL_BUFFER_SIZE:
return true;
+ case GL_BUFFER_ACCESS_OES:
+ return extensions.mapBuffer;
+
+ case GL_BUFFER_MAPPED:
+ static_assert(GL_BUFFER_MAPPED == GL_BUFFER_MAPPED_OES, "GL enums should be equal.");
+ return (context->getClientVersion() >= 3) || extensions.mapBuffer || extensions.mapBufferRange;
+
// GL_BUFFER_MAP_POINTER is a special case, and may only be
// queried with GetBufferPointerv
case GL_BUFFER_ACCESS_FLAGS:
- case GL_BUFFER_MAPPED:
case GL_BUFFER_MAP_OFFSET:
case GL_BUFFER_MAP_LENGTH:
- return (context->getClientVersion() >= 3);
+ return (context->getClientVersion() >= 3) || extensions.mapBufferRange;
default:
return false;
}
}
-bool ValidMipLevel(const Context *context, GLenum target, GLint level)
+bool ValidMipLevel(const ValidationContext *context, GLenum target, GLint level)
{
+ const auto &caps = context->getCaps();
size_t maxDimension = 0;
switch (target)
{
- case GL_TEXTURE_2D: maxDimension = context->getCaps().max2DTextureSize; break;
+ case GL_TEXTURE_2D:
+ maxDimension = caps.max2DTextureSize;
+ break;
case GL_TEXTURE_CUBE_MAP:
case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
- case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: maxDimension = context->getCaps().maxCubeMapTextureSize; break;
- case GL_TEXTURE_3D: maxDimension = context->getCaps().max3DTextureSize; break;
- case GL_TEXTURE_2D_ARRAY: maxDimension = context->getCaps().max2DTextureSize; break;
+ case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
+ maxDimension = caps.maxCubeMapTextureSize;
+ break;
+ case GL_TEXTURE_3D:
+ maxDimension = caps.max3DTextureSize;
+ break;
+ case GL_TEXTURE_2D_ARRAY:
+ maxDimension = caps.max2DTextureSize;
+ break;
default: UNREACHABLE();
}
- return level <= gl::log2(maxDimension);
+ return level <= gl::log2(static_cast<int>(maxDimension));
}
-bool ValidImageSize(const Context *context, GLenum target, GLint level,
- GLsizei width, GLsizei height, GLsizei depth)
+bool ValidImageSizeParameters(const Context *context,
+ GLenum target,
+ GLint level,
+ GLsizei width,
+ GLsizei height,
+ GLsizei depth,
+ bool isSubImage)
{
if (level < 0 || width < 0 || height < 0 || depth < 0)
{
return false;
}
- if (!context->getExtensions().textureNPOT &&
+ // TexSubImage parameters can be NPOT without textureNPOT extension,
+ // as long as the destination texture is POT.
+ if (!isSubImage && !context->getExtensions().textureNPOT &&
(level != 0 && (!gl::isPow2(width) || !gl::isPow2(height) || !gl::isPow2(depth))))
{
return false;
@@ -191,7 +324,28 @@ bool ValidImageSize(const Context *context, GLenum target, GLint level,
return true;
}
-bool ValidCompressedImageSize(const Context *context, GLenum internalFormat, GLsizei width, GLsizei height)
+bool CompressedTextureFormatRequiresExactSize(GLenum internalFormat)
+{
+ // List of compressed format that require that the texture size is smaller than or a multiple of
+ // the compressed block size.
+ switch (internalFormat)
+ {
+ case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
+ case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
+ case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
+ case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
+ case GL_ETC1_RGB8_LOSSY_DECODE_ANGLE:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+bool ValidCompressedImageSize(const ValidationContext *context,
+ GLenum internalFormat,
+ GLsizei width,
+ GLsizei height)
{
const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat);
if (!formatInfo.compressed)
@@ -199,12 +353,22 @@ bool ValidCompressedImageSize(const Context *context, GLenum internalFormat, GLs
return false;
}
- if (width < 0 || (static_cast<GLuint>(width) > formatInfo.compressedBlockWidth && width % formatInfo.compressedBlockWidth != 0) ||
- height < 0 || (static_cast<GLuint>(height) > formatInfo.compressedBlockHeight && height % formatInfo.compressedBlockHeight != 0))
+ if (width < 0 || height < 0)
{
return false;
}
+ if (CompressedTextureFormatRequiresExactSize(internalFormat))
+ {
+ if ((static_cast<GLuint>(width) > formatInfo.compressedBlockWidth &&
+ width % formatInfo.compressedBlockWidth != 0) ||
+ (static_cast<GLuint>(height) > formatInfo.compressedBlockHeight &&
+ height % formatInfo.compressedBlockHeight != 0))
+ {
+ return false;
+ }
+ }
+
return true;
}
@@ -220,33 +384,57 @@ bool ValidQueryType(const Context *context, GLenum queryType)
return true;
case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
return (context->getClientVersion() >= 3);
+ case GL_TIME_ELAPSED_EXT:
+ return context->getExtensions().disjointTimerQuery;
default:
return false;
}
}
-bool ValidProgram(Context *context, GLuint id)
+Program *GetValidProgram(Context *context, GLuint id)
{
// ES3 spec (section 2.11.1) -- "Commands that accept shader or program object names will generate the
// error INVALID_VALUE if the provided name is not the name of either a shader or program object and
// INVALID_OPERATION if the provided name identifies an object that is not the expected type."
- if (context->getProgram(id) != NULL)
- {
- return true;
- }
- else if (context->getShader(id) != NULL)
+ Program *validProgram = context->getProgram(id);
+
+ if (!validProgram)
{
- // ID is the wrong type
- context->recordError(Error(GL_INVALID_OPERATION));
- return false;
+ if (context->getShader(id))
+ {
+ context->recordError(
+ Error(GL_INVALID_OPERATION, "Expected a program name, but found a shader name"));
+ }
+ else
+ {
+ context->recordError(Error(GL_INVALID_VALUE, "Program name is not valid"));
+ }
}
- else
+
+ return validProgram;
+}
+
+Shader *GetValidShader(Context *context, GLuint id)
+{
+ // See ValidProgram for spec details.
+
+ Shader *validShader = context->getShader(id);
+
+ if (!validShader)
{
- // No shader/program object has this ID
- context->recordError(Error(GL_INVALID_VALUE));
- return false;
+ if (context->getProgram(id))
+ {
+ context->recordError(
+ Error(GL_INVALID_OPERATION, "Expected a shader name, but found a program name"));
+ }
+ else
+ {
+ context->recordError(Error(GL_INVALID_VALUE, "Shader name is invalid"));
+ }
}
+
+ return validShader;
}
bool ValidateAttachmentTarget(gl::Context *context, GLenum attachment)
@@ -343,9 +531,9 @@ bool ValidateRenderbufferStorageParametersANGLE(gl::Context *context, GLenum tar
ASSERT(samples == 0 || context->getExtensions().framebufferMultisample);
// ANGLE_framebuffer_multisample states that the value of samples must be less than or equal
- // to MAX_SAMPLES_ANGLE (Context::getExtensions().maxSamples) otherwise GL_INVALID_VALUE is
+ // to MAX_SAMPLES_ANGLE (Context::getCaps().maxSamples) otherwise GL_INVALID_VALUE is
// generated.
- if (static_cast<GLuint>(samples) > context->getExtensions().maxSamples)
+ if (static_cast<GLuint>(samples) > context->getCaps().maxSamples)
{
context->recordError(Error(GL_INVALID_VALUE));
return false;
@@ -354,11 +542,15 @@ bool ValidateRenderbufferStorageParametersANGLE(gl::Context *context, GLenum tar
// ANGLE_framebuffer_multisample states GL_OUT_OF_MEMORY is generated on a failure to create
// the specified storage. This is different than ES 3.0 in which a sample number higher
// than the maximum sample number supported by this format generates a GL_INVALID_VALUE.
- const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
- if (static_cast<GLuint>(samples) > formatCaps.getMaxSamples())
+ // The TextureCaps::getMaxSamples method is only guarenteed to be valid when the context is ES3.
+ if (context->getClientVersion() >= 3)
{
- context->recordError(Error(GL_OUT_OF_MEMORY));
- return false;
+ const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
+ if (static_cast<GLuint>(samples) > formatCaps.getMaxSamples())
+ {
+ context->recordError(Error(GL_OUT_OF_MEMORY));
+ return false;
+ }
}
return ValidateRenderbufferStorageParametersBase(context, target, samples, internalformat, width, height);
@@ -374,11 +566,11 @@ bool ValidateFramebufferRenderbufferParameters(gl::Context *context, GLenum targ
}
gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
- GLuint framebufferHandle = context->getState().getTargetFramebuffer(target)->id();
- if (!framebuffer || (framebufferHandle == 0 && renderbuffer != 0))
+ ASSERT(framebuffer);
+ if (framebuffer->id() == 0)
{
- context->recordError(Error(GL_INVALID_OPERATION));
+ context->recordError(Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
return false;
}
@@ -403,44 +595,23 @@ bool ValidateFramebufferRenderbufferParameters(gl::Context *context, GLenum targ
return true;
}
-static bool IsPartialBlit(gl::Context *context, gl::FramebufferAttachment *readBuffer, gl::FramebufferAttachment *writeBuffer,
- GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
- GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1)
-{
- if (srcX0 != 0 || srcY0 != 0 || dstX0 != 0 || dstY0 != 0 ||
- dstX1 != writeBuffer->getWidth() || dstY1 != writeBuffer->getHeight() ||
- srcX1 != readBuffer->getWidth() || srcY1 != readBuffer->getHeight())
- {
- return true;
- }
- else if (context->getState().isScissorTestEnabled())
- {
- const Rectangle &scissor = context->getState().getScissor();
-
- return scissor.x > 0 || scissor.y > 0 ||
- scissor.width < writeBuffer->getWidth() ||
- scissor.height < writeBuffer->getHeight();
- }
- else
- {
- return false;
- }
-}
-
-bool ValidateBlitFramebufferParameters(gl::Context *context, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
- GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask,
- GLenum filter, bool fromAngleExtension)
+bool ValidateBlitFramebufferParameters(gl::Context *context,
+ GLint srcX0,
+ GLint srcY0,
+ GLint srcX1,
+ GLint srcY1,
+ GLint dstX0,
+ GLint dstY0,
+ GLint dstX1,
+ GLint dstY1,
+ GLbitfield mask,
+ GLenum filter)
{
switch (filter)
{
case GL_NEAREST:
break;
case GL_LINEAR:
- if (fromAngleExtension)
- {
- context->recordError(Error(GL_INVALID_ENUM));
- return false;
- }
break;
default:
context->recordError(Error(GL_INVALID_ENUM));
@@ -460,13 +631,6 @@ bool ValidateBlitFramebufferParameters(gl::Context *context, GLint srcX0, GLint
return false;
}
- if (fromAngleExtension && (srcX1 - srcX0 != dstX1 - dstX0 || srcY1 - srcY0 != dstY1 - dstY0))
- {
- ERR("Scaling and flipping in BlitFramebufferANGLE not supported by this implementation.");
- context->recordError(Error(GL_INVALID_OPERATION));
- return false;
- }
-
// ES3.0 spec, section 4.3.2 states that linear filtering is only available for the
// color buffer, leaving only nearest being unfiltered from above
if ((mask & ~GL_COLOR_BUFFER_BIT) != 0 && filter != GL_NEAREST)
@@ -477,17 +641,12 @@ bool ValidateBlitFramebufferParameters(gl::Context *context, GLint srcX0, GLint
if (context->getState().getReadFramebuffer()->id() == context->getState().getDrawFramebuffer()->id())
{
- if (fromAngleExtension)
- {
- ERR("Blits with the same source and destination framebuffer are not supported by this "
- "implementation.");
- }
context->recordError(Error(GL_INVALID_OPERATION));
return false;
}
- gl::Framebuffer *readFramebuffer = context->getState().getReadFramebuffer();
- gl::Framebuffer *drawFramebuffer = context->getState().getDrawFramebuffer();
+ const gl::Framebuffer *readFramebuffer = context->getState().getReadFramebuffer();
+ const gl::Framebuffer *drawFramebuffer = context->getState().getDrawFramebuffer();
if (!readFramebuffer || !drawFramebuffer)
{
@@ -517,39 +676,68 @@ bool ValidateBlitFramebufferParameters(gl::Context *context, GLint srcX0, GLint
if (mask & GL_COLOR_BUFFER_BIT)
{
- gl::FramebufferAttachment *readColorBuffer = readFramebuffer->getReadColorbuffer();
- gl::FramebufferAttachment *drawColorBuffer = drawFramebuffer->getFirstColorbuffer();
+ const gl::FramebufferAttachment *readColorBuffer = readFramebuffer->getReadColorbuffer();
+ const gl::FramebufferAttachment *drawColorBuffer = drawFramebuffer->getFirstColorbuffer();
+ const Extensions &extensions = context->getExtensions();
if (readColorBuffer && drawColorBuffer)
{
GLenum readInternalFormat = readColorBuffer->getInternalFormat();
const InternalFormat &readFormatInfo = GetInternalFormatInfo(readInternalFormat);
- for (GLuint i = 0; i < context->getCaps().maxColorAttachments; i++)
+ for (size_t drawbufferIdx = 0;
+ drawbufferIdx < drawFramebuffer->getDrawbufferStateCount(); ++drawbufferIdx)
{
- if (drawFramebuffer->isEnabledColorAttachment(i))
+ const FramebufferAttachment *attachment =
+ drawFramebuffer->getDrawBuffer(drawbufferIdx);
+ if (attachment)
{
- GLenum drawInternalFormat = drawFramebuffer->getColorbuffer(i)->getInternalFormat();
+ GLenum drawInternalFormat = attachment->getInternalFormat();
const InternalFormat &drawFormatInfo = GetInternalFormatInfo(drawInternalFormat);
// The GL ES 3.0.2 spec (pg 193) states that:
// 1) If the read buffer is fixed point format, the draw buffer must be as well
// 2) If the read buffer is an unsigned integer format, the draw buffer must be as well
// 3) If the read buffer is a signed integer format, the draw buffer must be as well
- if ( (readFormatInfo.componentType == GL_UNSIGNED_NORMALIZED || readFormatInfo.componentType == GL_SIGNED_NORMALIZED) &&
- !(drawFormatInfo.componentType == GL_UNSIGNED_NORMALIZED || drawFormatInfo.componentType == GL_SIGNED_NORMALIZED))
+ // Changes with EXT_color_buffer_float:
+ // Case 1) is changed to fixed point OR floating point
+ GLenum readComponentType = readFormatInfo.componentType;
+ GLenum drawComponentType = drawFormatInfo.componentType;
+ bool readFixedPoint = (readComponentType == GL_UNSIGNED_NORMALIZED ||
+ readComponentType == GL_SIGNED_NORMALIZED);
+ bool drawFixedPoint = (drawComponentType == GL_UNSIGNED_NORMALIZED ||
+ drawComponentType == GL_SIGNED_NORMALIZED);
+
+ if (extensions.colorBufferFloat)
{
- context->recordError(Error(GL_INVALID_OPERATION));
+ bool readFixedOrFloat = (readFixedPoint || readComponentType == GL_FLOAT);
+ bool drawFixedOrFloat = (drawFixedPoint || drawComponentType == GL_FLOAT);
+
+ if (readFixedOrFloat != drawFixedOrFloat)
+ {
+ context->recordError(Error(GL_INVALID_OPERATION,
+ "If the read buffer contains fixed-point or "
+ "floating-point values, the draw buffer "
+ "must as well."));
+ return false;
+ }
+ }
+ else if (readFixedPoint != drawFixedPoint)
+ {
+ context->recordError(Error(GL_INVALID_OPERATION,
+ "If the read buffer contains fixed-point "
+ "values, the draw buffer must as well."));
return false;
}
- if (readFormatInfo.componentType == GL_UNSIGNED_INT && drawFormatInfo.componentType != GL_UNSIGNED_INT)
+ if (readComponentType == GL_UNSIGNED_INT &&
+ drawComponentType != GL_UNSIGNED_INT)
{
context->recordError(Error(GL_INVALID_OPERATION));
return false;
}
- if (readFormatInfo.componentType == GL_INT && drawFormatInfo.componentType != GL_INT)
+ if (readComponentType == GL_INT && drawComponentType != GL_INT)
{
context->recordError(Error(GL_INVALID_OPERATION));
return false;
@@ -568,53 +756,6 @@ bool ValidateBlitFramebufferParameters(gl::Context *context, GLint srcX0, GLint
context->recordError(Error(GL_INVALID_OPERATION));
return false;
}
-
- if (fromAngleExtension)
- {
- FramebufferAttachment *readColorAttachment = readFramebuffer->getReadColorbuffer();
- if (!readColorAttachment ||
- (!(readColorAttachment->type() == GL_TEXTURE && readColorAttachment->getTextureImageIndex()->type == GL_TEXTURE_2D) &&
- readColorAttachment->type() != GL_RENDERBUFFER &&
- readColorAttachment->type() != GL_FRAMEBUFFER_DEFAULT))
- {
- context->recordError(Error(GL_INVALID_OPERATION));
- return false;
- }
-
- for (GLuint colorAttachment = 0; colorAttachment < context->getCaps().maxColorAttachments; ++colorAttachment)
- {
- if (drawFramebuffer->isEnabledColorAttachment(colorAttachment))
- {
- FramebufferAttachment *attachment = drawFramebuffer->getColorbuffer(colorAttachment);
- ASSERT(attachment);
-
- if (!(attachment->type() == GL_TEXTURE && attachment->getTextureImageIndex()->type == GL_TEXTURE_2D) &&
- attachment->type() != GL_RENDERBUFFER &&
- attachment->type() != GL_FRAMEBUFFER_DEFAULT)
- {
- context->recordError(Error(GL_INVALID_OPERATION));
- return false;
- }
-
- // Return an error if the destination formats do not match
- if (attachment->getInternalFormat() != readColorBuffer->getInternalFormat())
- {
- context->recordError(Error(GL_INVALID_OPERATION));
- return false;
- }
- }
- }
-
- int readSamples = readFramebuffer->getSamples(context->getData());
-
- if (readSamples != 0 && IsPartialBlit(context, readColorBuffer, drawColorBuffer,
- srcX0, srcY0, srcX1, srcY1,
- dstX0, dstY0, dstX1, dstY1))
- {
- context->recordError(Error(GL_INVALID_OPERATION));
- return false;
- }
- }
}
}
@@ -624,8 +765,8 @@ bool ValidateBlitFramebufferParameters(gl::Context *context, GLint srcX0, GLint
{
if (mask & masks[i])
{
- gl::FramebufferAttachment *readBuffer = readFramebuffer->getAttachment(attachments[i]);
- gl::FramebufferAttachment *drawBuffer = drawFramebuffer->getAttachment(attachments[i]);
+ const gl::FramebufferAttachment *readBuffer = readFramebuffer->getAttachment(attachments[i]);
+ const gl::FramebufferAttachment *drawBuffer = drawFramebuffer->getAttachment(attachments[i]);
if (readBuffer && drawBuffer)
{
@@ -640,23 +781,6 @@ bool ValidateBlitFramebufferParameters(gl::Context *context, GLint srcX0, GLint
context->recordError(Error(GL_INVALID_OPERATION));
return false;
}
-
- if (fromAngleExtension)
- {
- if (IsPartialBlit(context, readBuffer, drawBuffer,
- srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1))
- {
- ERR("Only whole-buffer depth and stencil blits are supported by this implementation.");
- context->recordError(Error(GL_INVALID_OPERATION)); // only whole-buffer copies are permitted
- return false;
- }
-
- if (readBuffer->getSamples() != 0 || drawBuffer->getSamples() != 0)
- {
- context->recordError(Error(GL_INVALID_OPERATION));
- return false;
- }
- }
}
}
}
@@ -886,10 +1010,22 @@ bool ValidateSamplerObjectParameter(gl::Context *context, GLenum pname)
}
}
-bool ValidateReadPixelsParameters(gl::Context *context, GLint x, GLint y, GLsizei width, GLsizei height,
- GLenum format, GLenum type, GLsizei *bufSize, GLvoid *pixels)
+bool ValidateReadPixels(Context *context,
+ GLint x,
+ GLint y,
+ GLsizei width,
+ GLsizei height,
+ GLenum format,
+ GLenum type,
+ GLvoid *pixels)
{
- gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
+ if (width < 0 || height < 0)
+ {
+ context->recordError(Error(GL_INVALID_VALUE, "width and height must be positive"));
+ return false;
+ }
+
+ Framebuffer *framebuffer = context->getState().getReadFramebuffer();
ASSERT(framebuffer);
if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
@@ -926,35 +1062,99 @@ bool ValidateReadPixelsParameters(gl::Context *context, GLint x, GLint y, GLsize
return false;
}
+ return true;
+}
+
+bool ValidateReadnPixelsEXT(Context *context,
+ GLint x,
+ GLint y,
+ GLsizei width,
+ GLsizei height,
+ GLenum format,
+ GLenum type,
+ GLsizei bufSize,
+ GLvoid *pixels)
+{
+ if (bufSize < 0)
+ {
+ context->recordError(Error(GL_INVALID_VALUE, "bufSize must be a positive number"));
+ return false;
+ }
+
GLenum sizedInternalFormat = GetSizedInternalFormat(format, type);
const InternalFormat &sizedFormatInfo = GetInternalFormatInfo(sizedInternalFormat);
- GLsizei outputPitch = sizedFormatInfo.computeRowPitch(type, width, context->getState().getPackAlignment(), 0);
+ GLsizei outputPitch =
+ sizedFormatInfo.computeRowPitch(type, width, context->getState().getPackAlignment(),
+ context->getState().getPackRowLength());
// sized query sanity check
- if (bufSize)
+ int requiredSize = outputPitch * height;
+ if (requiredSize > bufSize)
{
- int requiredSize = outputPitch * height;
- if (requiredSize > *bufSize)
- {
- context->recordError(Error(GL_INVALID_OPERATION));
- return false;
- }
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
+ }
+
+ return ValidateReadPixels(context, x, y, width, height, format, type, pixels);
+}
+
+bool ValidateGenQueriesBase(gl::Context *context, GLsizei n, const GLuint *ids)
+{
+ if (n < 0)
+ {
+ context->recordError(Error(GL_INVALID_VALUE, "Query count < 0"));
+ return false;
}
return true;
}
-bool ValidateBeginQuery(gl::Context *context, GLenum target, GLuint id)
+bool ValidateGenQueriesEXT(gl::Context *context, GLsizei n, const GLuint *ids)
+{
+ if (!context->getExtensions().occlusionQueryBoolean &&
+ !context->getExtensions().disjointTimerQuery)
+ {
+ context->recordError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
+ return false;
+ }
+
+ return ValidateGenQueriesBase(context, n, ids);
+}
+
+bool ValidateDeleteQueriesBase(gl::Context *context, GLsizei n, const GLuint *ids)
+{
+ if (n < 0)
+ {
+ context->recordError(Error(GL_INVALID_VALUE, "Query count < 0"));
+ return false;
+ }
+
+ return true;
+}
+
+bool ValidateDeleteQueriesEXT(gl::Context *context, GLsizei n, const GLuint *ids)
+{
+ if (!context->getExtensions().occlusionQueryBoolean &&
+ !context->getExtensions().disjointTimerQuery)
+ {
+ context->recordError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
+ return false;
+ }
+
+ return ValidateDeleteQueriesBase(context, n, ids);
+}
+
+bool ValidateBeginQueryBase(gl::Context *context, GLenum target, GLuint id)
{
if (!ValidQueryType(context, target))
{
- context->recordError(Error(GL_INVALID_ENUM));
+ context->recordError(Error(GL_INVALID_ENUM, "Invalid query target"));
return false;
}
if (id == 0)
{
- context->recordError(Error(GL_INVALID_OPERATION));
+ context->recordError(Error(GL_INVALID_OPERATION, "Query id is 0"));
return false;
}
@@ -973,9 +1173,12 @@ bool ValidateBeginQuery(gl::Context *context, GLenum target, GLuint id)
// b) There are no active queries for the requested target (and in the case
// of GL_ANY_SAMPLES_PASSED_EXT and GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
// no query may be active for either if glBeginQuery targets either.
+
+ // TODO(ewell): I think this needs to be changed for timer and occlusion queries to work at the
+ // same time
if (context->getState().isQueryActive())
{
- context->recordError(Error(GL_INVALID_OPERATION));
+ context->recordError(Error(GL_INVALID_OPERATION, "Other query is active"));
return false;
}
@@ -984,41 +1187,215 @@ bool ValidateBeginQuery(gl::Context *context, GLenum target, GLuint id)
// check that name was obtained with glGenQueries
if (!queryObject)
{
- context->recordError(Error(GL_INVALID_OPERATION));
+ context->recordError(Error(GL_INVALID_OPERATION, "Invalid query id"));
return false;
}
// check for type mismatch
if (queryObject->getType() != target)
{
- context->recordError(Error(GL_INVALID_OPERATION));
+ context->recordError(Error(GL_INVALID_OPERATION, "Query type does not match target"));
return false;
}
return true;
}
-bool ValidateEndQuery(gl::Context *context, GLenum target)
+bool ValidateBeginQueryEXT(gl::Context *context, GLenum target, GLuint id)
+{
+ if (!context->getExtensions().occlusionQueryBoolean &&
+ !context->getExtensions().disjointTimerQuery)
+ {
+ context->recordError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
+ return false;
+ }
+
+ return ValidateBeginQueryBase(context, target, id);
+}
+
+bool ValidateEndQueryBase(gl::Context *context, GLenum target)
{
if (!ValidQueryType(context, target))
{
- context->recordError(Error(GL_INVALID_ENUM));
+ context->recordError(Error(GL_INVALID_ENUM, "Invalid query target"));
return false;
}
const Query *queryObject = context->getState().getActiveQuery(target);
- if (queryObject == NULL)
+ if (queryObject == nullptr)
{
- context->recordError(Error(GL_INVALID_OPERATION));
+ context->recordError(Error(GL_INVALID_OPERATION, "Query target not active"));
return false;
}
return true;
}
-static bool ValidateUniformCommonBase(gl::Context *context, GLenum targetUniformType,
- GLint location, GLsizei count, LinkedUniform **uniformOut)
+bool ValidateEndQueryEXT(gl::Context *context, GLenum target)
+{
+ if (!context->getExtensions().occlusionQueryBoolean &&
+ !context->getExtensions().disjointTimerQuery)
+ {
+ context->recordError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
+ return false;
+ }
+
+ return ValidateEndQueryBase(context, target);
+}
+
+bool ValidateQueryCounterEXT(Context *context, GLuint id, GLenum target)
+{
+ if (!context->getExtensions().disjointTimerQuery)
+ {
+ context->recordError(Error(GL_INVALID_OPERATION, "Disjoint timer query not enabled"));
+ return false;
+ }
+
+ if (target != GL_TIMESTAMP_EXT)
+ {
+ context->recordError(Error(GL_INVALID_ENUM, "Invalid query target"));
+ return false;
+ }
+
+ Query *queryObject = context->getQuery(id, true, target);
+ if (queryObject == nullptr)
+ {
+ context->recordError(Error(GL_INVALID_OPERATION, "Invalid query id"));
+ return false;
+ }
+
+ if (context->getState().isQueryActive(queryObject))
+ {
+ context->recordError(Error(GL_INVALID_OPERATION, "Query is active"));
+ return false;
+ }
+
+ return true;
+}
+
+bool ValidateGetQueryivBase(Context *context, GLenum target, GLenum pname)
+{
+ if (!ValidQueryType(context, target) && target != GL_TIMESTAMP_EXT)
+ {
+ context->recordError(Error(GL_INVALID_ENUM, "Invalid query type"));
+ return false;
+ }
+
+ switch (pname)
+ {
+ case GL_CURRENT_QUERY_EXT:
+ if (target == GL_TIMESTAMP_EXT)
+ {
+ context->recordError(
+ Error(GL_INVALID_ENUM, "Cannot use current query for timestamp"));
+ return false;
+ }
+ break;
+ case GL_QUERY_COUNTER_BITS_EXT:
+ if (!context->getExtensions().disjointTimerQuery ||
+ (target != GL_TIMESTAMP_EXT && target != GL_TIME_ELAPSED_EXT))
+ {
+ context->recordError(Error(GL_INVALID_ENUM, "Invalid pname"));
+ return false;
+ }
+ break;
+ default:
+ context->recordError(Error(GL_INVALID_ENUM, "Invalid pname"));
+ return false;
+ }
+
+ return true;
+}
+
+bool ValidateGetQueryivEXT(Context *context, GLenum target, GLenum pname, GLint *params)
+{
+ if (!context->getExtensions().occlusionQueryBoolean &&
+ !context->getExtensions().disjointTimerQuery)
+ {
+ context->recordError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
+ return false;
+ }
+
+ return ValidateGetQueryivBase(context, target, pname);
+}
+
+bool ValidateGetQueryObjectValueBase(Context *context, GLuint id, GLenum pname)
+{
+ Query *queryObject = context->getQuery(id, false, GL_NONE);
+
+ if (!queryObject)
+ {
+ context->recordError(Error(GL_INVALID_OPERATION, "Query does not exist"));
+ return false;
+ }
+
+ if (context->getState().isQueryActive(queryObject))
+ {
+ context->recordError(Error(GL_INVALID_OPERATION, "Query currently active"));
+ return false;
+ }
+
+ switch (pname)
+ {
+ case GL_QUERY_RESULT_EXT:
+ case GL_QUERY_RESULT_AVAILABLE_EXT:
+ break;
+
+ default:
+ context->recordError(Error(GL_INVALID_ENUM, "Invalid pname enum"));
+ return false;
+ }
+
+ return true;
+}
+
+bool ValidateGetQueryObjectivEXT(Context *context, GLuint id, GLenum pname, GLint *params)
+{
+ if (!context->getExtensions().disjointTimerQuery)
+ {
+ context->recordError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
+ return false;
+ }
+ return ValidateGetQueryObjectValueBase(context, id, pname);
+}
+
+bool ValidateGetQueryObjectuivEXT(Context *context, GLuint id, GLenum pname, GLuint *params)
+{
+ if (!context->getExtensions().disjointTimerQuery &&
+ !context->getExtensions().occlusionQueryBoolean)
+ {
+ context->recordError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
+ return false;
+ }
+ return ValidateGetQueryObjectValueBase(context, id, pname);
+}
+
+bool ValidateGetQueryObjecti64vEXT(Context *context, GLuint id, GLenum pname, GLint64 *params)
+{
+ if (!context->getExtensions().disjointTimerQuery)
+ {
+ context->recordError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
+ return false;
+ }
+ return ValidateGetQueryObjectValueBase(context, id, pname);
+}
+
+bool ValidateGetQueryObjectui64vEXT(Context *context, GLuint id, GLenum pname, GLuint64 *params)
+{
+ if (!context->getExtensions().disjointTimerQuery)
+ {
+ context->recordError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
+ return false;
+ }
+ return ValidateGetQueryObjectValueBase(context, id, pname);
+}
+
+static bool ValidateUniformCommonBase(gl::Context *context,
+ GLenum targetUniformType,
+ GLint location,
+ GLsizei count,
+ const LinkedUniform **uniformOut)
{
if (count < 0)
{
@@ -1045,16 +1422,16 @@ static bool ValidateUniformCommonBase(gl::Context *context, GLenum targetUniform
return false;
}
- LinkedUniform *uniform = program->getUniformByLocation(location);
+ const LinkedUniform &uniform = program->getUniformByLocation(location);
// attempting to write an array to a non-array uniform is an INVALID_OPERATION
- if (uniform->elementCount() == 1 && count > 1)
+ if (!uniform.isArray() && count > 1)
{
context->recordError(Error(GL_INVALID_OPERATION));
return false;
}
- *uniformOut = uniform;
+ *uniformOut = &uniform;
return true;
}
@@ -1067,7 +1444,7 @@ bool ValidateUniform(gl::Context *context, GLenum uniformType, GLint location, G
return false;
}
- LinkedUniform *uniform = NULL;
+ const LinkedUniform *uniform = nullptr;
if (!ValidateUniformCommonBase(context, uniformType, location, count, &uniform))
{
return false;
@@ -1102,7 +1479,7 @@ bool ValidateUniformMatrix(gl::Context *context, GLenum matrixType, GLint locati
return false;
}
- LinkedUniform *uniform = NULL;
+ const LinkedUniform *uniform = nullptr;
if (!ValidateUniformCommonBase(context, matrixType, location, count, &uniform))
{
return false;
@@ -1162,7 +1539,7 @@ bool ValidateStateQuery(gl::Context *context, GLenum pname, GLenum *nativeType,
return false;
}
- FramebufferAttachment *attachment = framebuffer->getReadColorbuffer();
+ const FramebufferAttachment *attachment = framebuffer->getReadColorbuffer();
if (!attachment)
{
context->recordError(Error(GL_INVALID_OPERATION));
@@ -1184,17 +1561,21 @@ bool ValidateStateQuery(gl::Context *context, GLenum pname, GLenum *nativeType,
return true;
}
-bool ValidateCopyTexImageParametersBase(gl::Context* context, GLenum target, GLint level, GLenum internalformat, bool isSubImage,
- GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height,
- GLint border, GLenum *textureFormatOut)
+bool ValidateCopyTexImageParametersBase(ValidationContext *context,
+ GLenum target,
+ GLint level,
+ GLenum internalformat,
+ bool isSubImage,
+ GLint xoffset,
+ GLint yoffset,
+ GLint zoffset,
+ GLint x,
+ GLint y,
+ GLsizei width,
+ GLsizei height,
+ GLint border,
+ GLenum *textureFormatOut)
{
-
- if (!ValidTexture2DDestinationTarget(context, target))
- {
- context->recordError(Error(GL_INVALID_ENUM));
- return false;
- }
-
if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0)
{
context->recordError(Error(GL_INVALID_VALUE));
@@ -1219,14 +1600,15 @@ bool ValidateCopyTexImageParametersBase(gl::Context* context, GLenum target, GLi
return false;
}
- gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
+ const gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
{
context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
return false;
}
- if (context->getState().getReadFramebuffer()->id() != 0 && framebuffer->getSamples(context->getData()) != 0)
+ const auto &state = context->getState();
+ if (state.getReadFramebuffer()->id() != 0 && framebuffer->getSamples(context->getData()) != 0)
{
context->recordError(Error(GL_INVALID_OPERATION));
return false;
@@ -1263,14 +1645,15 @@ bool ValidateCopyTexImageParametersBase(gl::Context* context, GLenum target, GLi
return false;
}
- gl::Texture *texture = context->getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target);
+ gl::Texture *texture =
+ state.getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target);
if (!texture)
{
context->recordError(Error(GL_INVALID_OPERATION));
return false;
}
- if (texture->isImmutable() && !isSubImage)
+ if (texture->getImmutableFormat() && !isSubImage)
{
context->recordError(Error(GL_INVALID_OPERATION));
return false;
@@ -1326,7 +1709,10 @@ bool ValidateCopyTexImageParametersBase(gl::Context* context, GLenum target, GLi
return true;
}
-static bool ValidateDrawBase(Context *context, GLenum mode, GLsizei count, GLsizei maxVertex, GLsizei primcount)
+static bool ValidateDrawBase(ValidationContext *context,
+ GLenum mode,
+ GLsizei count,
+ GLsizei primcount)
{
switch (mode)
{
@@ -1358,17 +1744,27 @@ static bool ValidateDrawBase(Context *context, GLenum mode, GLsizei count, GLsiz
return false;
}
- const gl::DepthStencilState &depthStencilState = state.getDepthStencilState();
- if (depthStencilState.stencilWritemask != depthStencilState.stencilBackWritemask ||
- state.getStencilRef() != state.getStencilBackRef() ||
- depthStencilState.stencilMask != depthStencilState.stencilBackMask)
+ if (context->getLimitations().noSeparateStencilRefsAndMasks)
{
- // Note: these separate values are not supported in WebGL, due to D3D's limitations.
- // See Section 6.10 of the WebGL 1.0 spec
- ERR("This ANGLE implementation does not support separate front/back stencil "
- "writemasks, reference values, or stencil mask values.");
- context->recordError(Error(GL_INVALID_OPERATION));
- return false;
+ const Framebuffer *framebuffer = context->getState().getDrawFramebuffer();
+ const FramebufferAttachment *stencilBuffer = framebuffer->getStencilbuffer();
+ GLuint stencilBits = stencilBuffer ? stencilBuffer->getStencilSize() : 0;
+ GLuint minimumRequiredStencilMask = (1 << stencilBits) - 1;
+ const DepthStencilState &depthStencilState = state.getDepthStencilState();
+ if ((depthStencilState.stencilWritemask & minimumRequiredStencilMask) !=
+ (depthStencilState.stencilBackWritemask & minimumRequiredStencilMask) ||
+ state.getStencilRef() != state.getStencilBackRef() ||
+ (depthStencilState.stencilMask & minimumRequiredStencilMask) !=
+ (depthStencilState.stencilBackMask & minimumRequiredStencilMask))
+ {
+ // Note: these separate values are not supported in WebGL, due to D3D's limitations. See
+ // Section 6.10 of the WebGL 1.0 spec
+ ERR(
+ "This ANGLE implementation does not support separate front/back stencil "
+ "writemasks, reference values, or stencil mask values.");
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
+ }
}
const gl::Framebuffer *fbo = state.getDrawFramebuffer();
@@ -1391,74 +1787,29 @@ static bool ValidateDrawBase(Context *context, GLenum mode, GLsizei count, GLsiz
return false;
}
- // Buffer validations
- const VertexArray *vao = state.getVertexArray();
- for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
- {
- const VertexAttribute &attrib = vao->getVertexAttribute(attributeIndex);
- bool attribActive = (program->getSemanticIndex(attributeIndex) != -1);
- if (attribActive && attrib.enabled)
- {
- gl::Buffer *buffer = attrib.buffer.get();
-
- if (buffer)
- {
- GLint64 attribStride = static_cast<GLint64>(ComputeVertexAttributeStride(attrib));
- GLint64 maxVertexElement = 0;
-
- if (attrib.divisor > 0)
- {
- maxVertexElement = static_cast<GLint64>(primcount) / static_cast<GLint64>(attrib.divisor);
- }
- else
- {
- maxVertexElement = static_cast<GLint64>(maxVertex);
- }
-
- GLint64 attribDataSize = maxVertexElement * attribStride;
-
- // [OpenGL ES 3.0.2] section 2.9.4 page 40:
- // We can return INVALID_OPERATION if our vertex attribute does not have
- // enough backing data.
- if (attribDataSize > buffer->getSize())
- {
- context->recordError(Error(GL_INVALID_OPERATION));
- return false;
- }
- }
- else if (attrib.pointer == NULL)
- {
- // This is an application error that would normally result in a crash,
- // but we catch it and return an error
- context->recordError(Error(GL_INVALID_OPERATION, "An enabled vertex array has no buffer and no pointer."));
- return false;
- }
- }
- }
-
// Uniform buffer validation
for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < program->getActiveUniformBlockCount(); uniformBlockIndex++)
{
- const gl::UniformBlock *uniformBlock = program->getUniformBlockByIndex(uniformBlockIndex);
+ const gl::UniformBlock &uniformBlock = program->getUniformBlockByIndex(uniformBlockIndex);
GLuint blockBinding = program->getUniformBlockBinding(uniformBlockIndex);
- const gl::Buffer *uniformBuffer = state.getIndexedUniformBuffer(blockBinding);
+ const OffsetBindingPointer<Buffer> &uniformBuffer =
+ state.getIndexedUniformBuffer(blockBinding);
- if (!uniformBuffer)
+ if (uniformBuffer.get() == nullptr)
{
// undefined behaviour
context->recordError(Error(GL_INVALID_OPERATION, "It is undefined behaviour to have a used but unbound uniform buffer."));
return false;
}
- size_t uniformBufferSize = state.getIndexedUniformBufferSize(blockBinding);
-
+ size_t uniformBufferSize = uniformBuffer.getSize();
if (uniformBufferSize == 0)
{
// Bind the whole buffer.
- uniformBufferSize = uniformBuffer->getSize();
+ uniformBufferSize = static_cast<size_t>(uniformBuffer->getSize());
}
- if (uniformBufferSize < uniformBlock->dataSize)
+ if (uniformBufferSize < uniformBlock.dataSize)
{
// undefined behaviour
context->recordError(Error(GL_INVALID_OPERATION, "It is undefined behaviour to use a uniform buffer that is too small."));
@@ -1480,8 +1831,8 @@ bool ValidateDrawArrays(Context *context, GLenum mode, GLint first, GLsizei coun
const State &state = context->getState();
gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
- if (curTransformFeedback && curTransformFeedback->isStarted() && !curTransformFeedback->isPaused() &&
- curTransformFeedback->getDrawMode() != mode)
+ if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused() &&
+ curTransformFeedback->getPrimitiveMode() != mode)
{
// It is an invalid operation to call DrawArrays or DrawArraysInstanced with a draw mode
// that does not match the current transform feedback object's draw mode (if transform feedback
@@ -1490,7 +1841,12 @@ bool ValidateDrawArrays(Context *context, GLenum mode, GLint first, GLsizei coun
return false;
}
- if (!ValidateDrawBase(context, mode, count, count, primcount))
+ if (!ValidateDrawBase(context, mode, count, primcount))
+ {
+ return false;
+ }
+
+ if (!ValidateDrawAttribs(context, primcount, count))
{
return false;
}
@@ -1523,11 +1879,10 @@ static bool ValidateDrawInstancedANGLE(Context *context)
gl::Program *program = state.getProgram();
const VertexArray *vao = state.getVertexArray();
- for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
+ for (size_t attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
{
const VertexAttribute &attrib = vao->getVertexAttribute(attributeIndex);
- bool active = (program->getSemanticIndex(attributeIndex) != -1);
- if (active && attrib.divisor == 0)
+ if (program->isAttribLocationActive(attributeIndex) && attrib.divisor == 0)
{
return true;
}
@@ -1548,8 +1903,13 @@ bool ValidateDrawArraysInstancedANGLE(Context *context, GLenum mode, GLint first
return ValidateDrawArraysInstanced(context, mode, first, count, primcount);
}
-bool ValidateDrawElements(Context *context, GLenum mode, GLsizei count, GLenum type,
- const GLvoid* indices, GLsizei primcount, rx::RangeUI *indexRangeOut)
+bool ValidateDrawElements(ValidationContext *context,
+ GLenum mode,
+ GLsizei count,
+ GLenum type,
+ const GLvoid *indices,
+ GLsizei primcount,
+ IndexRange *indexRangeOut)
{
switch (type)
{
@@ -1557,7 +1917,7 @@ bool ValidateDrawElements(Context *context, GLenum mode, GLsizei count, GLenum t
case GL_UNSIGNED_SHORT:
break;
case GL_UNSIGNED_INT:
- if (!context->getExtensions().elementIndexUint)
+ if (context->getClientVersion() < 3 && !context->getExtensions().elementIndexUint)
{
context->recordError(Error(GL_INVALID_ENUM));
return false;
@@ -1571,7 +1931,7 @@ bool ValidateDrawElements(Context *context, GLenum mode, GLsizei count, GLenum t
const State &state = context->getState();
gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
- if (curTransformFeedback && curTransformFeedback->isStarted() && !curTransformFeedback->isPaused())
+ if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused())
{
// It is an invalid operation to call DrawElements, DrawRangeElements or DrawElementsInstanced
// while transform feedback is active, (3.0.2, section 2.14, pg 86)
@@ -1587,7 +1947,7 @@ bool ValidateDrawElements(Context *context, GLenum mode, GLsizei count, GLenum t
}
const gl::VertexArray *vao = state.getVertexArray();
- gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer();
+ gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
if (!indices && !elementArrayBuffer)
{
context->recordError(Error(GL_INVALID_OPERATION));
@@ -1623,45 +1983,56 @@ bool ValidateDrawElements(Context *context, GLenum mode, GLsizei count, GLenum t
return false;
}
+ if (!ValidateDrawBase(context, mode, count, primcount))
+ {
+ return false;
+ }
+
// Use max index to validate if our vertex buffers are large enough for the pull.
// TODO: offer fast path, with disabled index validation.
// TODO: also disable index checking on back-ends that are robust to out-of-range accesses.
if (elementArrayBuffer)
{
uintptr_t offset = reinterpret_cast<uintptr_t>(indices);
- if (!elementArrayBuffer->getIndexRangeCache()->findRange(type, offset, count, indexRangeOut))
+ Error error =
+ elementArrayBuffer->getIndexRange(type, static_cast<size_t>(offset), count,
+ state.isPrimitiveRestartEnabled(), indexRangeOut);
+ if (error.isError())
{
- rx::BufferImpl *bufferImpl = elementArrayBuffer->getImplementation();
- const uint8_t *dataPointer = NULL;
- Error error = bufferImpl->getData(&dataPointer);
- if (error.isError())
- {
- context->recordError(error);
- return false;
- }
-
- const uint8_t *offsetPointer = dataPointer + offset;
- *indexRangeOut = rx::IndexRangeCache::ComputeRange(type, offsetPointer, count);
- elementArrayBuffer->getIndexRangeCache()->addRange(type, offset, count, *indexRangeOut);
+ context->recordError(error);
+ return false;
}
}
else
{
- *indexRangeOut = rx::IndexRangeCache::ComputeRange(type, indices, count);
+ *indexRangeOut = ComputeIndexRange(type, indices, count, state.isPrimitiveRestartEnabled());
}
- if (!ValidateDrawBase(context, mode, count, static_cast<GLsizei>(indexRangeOut->end), primcount))
+ // If we use an index greater than our maximum supported index range, return an error.
+ // The ES3 spec does not specify behaviour here, it is undefined, but ANGLE should always
+ // return an error if possible here.
+ if (static_cast<GLuint64>(indexRangeOut->end) >= context->getCaps().maxElementIndex)
{
+ context->recordError(Error(GL_INVALID_OPERATION, g_ExceedsMaxElementErrorMessage));
return false;
}
- return true;
+ if (!ValidateDrawAttribs(context, primcount, static_cast<GLsizei>(indexRangeOut->end)))
+ {
+ return false;
+ }
+
+ // No op if there are no real indices in the index data (all are primitive restart).
+ return (indexRangeOut->vertexIndexCount > 0);
}
bool ValidateDrawElementsInstanced(Context *context,
- GLenum mode, GLsizei count, GLenum type,
- const GLvoid *indices, GLsizei primcount,
- rx::RangeUI *indexRangeOut)
+ GLenum mode,
+ GLsizei count,
+ GLenum type,
+ const GLvoid *indices,
+ GLsizei primcount,
+ IndexRange *indexRangeOut)
{
if (primcount < 0)
{
@@ -1678,8 +2049,13 @@ bool ValidateDrawElementsInstanced(Context *context,
return (primcount > 0);
}
-bool ValidateDrawElementsInstancedANGLE(Context *context, GLenum mode, GLsizei count, GLenum type,
- const GLvoid *indices, GLsizei primcount, rx::RangeUI *indexRangeOut)
+bool ValidateDrawElementsInstancedANGLE(Context *context,
+ GLenum mode,
+ GLsizei count,
+ GLenum type,
+ const GLvoid *indices,
+ GLsizei primcount,
+ IndexRange *indexRangeOut)
{
if (!ValidateDrawInstancedANGLE(context))
{
@@ -1721,11 +2097,11 @@ bool ValidateFramebufferTextureBase(Context *context, GLenum target, GLenum atta
}
const gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
- GLuint framebufferHandle = context->getState().getTargetFramebuffer(target)->id();
+ ASSERT(framebuffer);
- if (framebufferHandle == 0 || !framebuffer)
+ if (framebuffer->id() == 0)
{
- context->recordError(Error(GL_INVALID_OPERATION));
+ context->recordError(Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
return false;
}
@@ -1735,8 +2111,8 @@ bool ValidateFramebufferTextureBase(Context *context, GLenum target, GLenum atta
bool ValidateFramebufferTexture2D(Context *context, GLenum target, GLenum attachment,
GLenum textarget, GLuint texture, GLint level)
{
- // Attachments are required to be bound to level 0 in ES2
- if (context->getClientVersion() < 3 && level != 0)
+ // Attachments are required to be bound to level 0 without ES3 or the GL_OES_fbo_render_mipmap extension
+ if (context->getClientVersion() < 3 && !context->getExtensions().fboRenderMipmap && level != 0)
{
context->recordError(Error(GL_INVALID_VALUE));
return false;
@@ -1815,13 +2191,12 @@ bool ValidateGetUniformBase(Context *context, GLuint program, GLint location)
return false;
}
- if (!ValidProgram(context, program))
+ gl::Program *programObject = GetValidProgram(context, program);
+ if (!programObject)
{
return false;
}
- gl::Program *programObject = context->getProgram(program);
-
if (!programObject || !programObject->isLinked())
{
context->recordError(Error(GL_INVALID_OPERATION));
@@ -1858,8 +2233,8 @@ static bool ValidateSizedGetUniform(Context *context, GLuint program, GLint loca
ASSERT(programObject);
// sized queries -- ensure the provided buffer is large enough
- LinkedUniform *uniform = programObject->getUniformByLocation(location);
- size_t requiredBytes = VariableExternalSize(uniform->type);
+ const LinkedUniform &uniform = programObject->getUniformByLocation(location);
+ size_t requiredBytes = VariableExternalSize(uniform.type);
if (static_cast<size_t>(bufSize) < requiredBytes)
{
context->recordError(Error(GL_INVALID_OPERATION));
@@ -1879,4 +2254,382 @@ bool ValidateGetnUniformivEXT(Context *context, GLuint program, GLint location,
return ValidateSizedGetUniform(context, program, location, bufSize);
}
+bool ValidateDiscardFramebufferBase(Context *context, GLenum target, GLsizei numAttachments,
+ const GLenum *attachments, bool defaultFramebuffer)
+{
+ if (numAttachments < 0)
+ {
+ context->recordError(Error(GL_INVALID_VALUE, "numAttachments must not be less than zero"));
+ return false;
+ }
+
+ for (GLsizei i = 0; i < numAttachments; ++i)
+ {
+ if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT15)
+ {
+ if (defaultFramebuffer)
+ {
+ context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is bound"));
+ return false;
+ }
+
+ if (attachments[i] >= GL_COLOR_ATTACHMENT0 + context->getCaps().maxColorAttachments)
+ {
+ context->recordError(Error(GL_INVALID_OPERATION,
+ "Requested color attachment is greater than the maximum supported color attachments"));
+ return false;
+ }
+ }
+ else
+ {
+ switch (attachments[i])
+ {
+ case GL_DEPTH_ATTACHMENT:
+ case GL_STENCIL_ATTACHMENT:
+ case GL_DEPTH_STENCIL_ATTACHMENT:
+ if (defaultFramebuffer)
+ {
+ context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is bound"));
+ return false;
+ }
+ break;
+ case GL_COLOR:
+ case GL_DEPTH:
+ case GL_STENCIL:
+ if (!defaultFramebuffer)
+ {
+ context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is not bound"));
+ return false;
+ }
+ break;
+ default:
+ context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment"));
+ return false;
+ }
+ }
+ }
+
+ return true;
}
+
+bool ValidateInsertEventMarkerEXT(Context *context, GLsizei length, const char *marker)
+{
+ // Note that debug marker calls must not set error state
+
+ if (length < 0)
+ {
+ return false;
+ }
+
+ if (marker == nullptr)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+bool ValidatePushGroupMarkerEXT(Context *context, GLsizei length, const char *marker)
+{
+ // Note that debug marker calls must not set error state
+
+ if (length < 0)
+ {
+ return false;
+ }
+
+ if (length > 0 && marker == nullptr)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+bool ValidateEGLImageTargetTexture2DOES(Context *context,
+ egl::Display *display,
+ GLenum target,
+ egl::Image *image)
+{
+ if (!context->getExtensions().eglImage && !context->getExtensions().eglImageExternal)
+ {
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
+ }
+
+ switch (target)
+ {
+ case GL_TEXTURE_2D:
+ break;
+
+ default:
+ context->recordError(Error(GL_INVALID_ENUM, "invalid texture target."));
+ return false;
+ }
+
+ if (!display->isValidImage(image))
+ {
+ context->recordError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
+ return false;
+ }
+
+ if (image->getSamples() > 0)
+ {
+ context->recordError(Error(GL_INVALID_OPERATION,
+ "cannot create a 2D texture from a multisampled EGL image."));
+ return false;
+ }
+
+ const TextureCaps &textureCaps = context->getTextureCaps().get(image->getInternalFormat());
+ if (!textureCaps.texturable)
+ {
+ context->recordError(Error(GL_INVALID_OPERATION,
+ "EGL image internal format is not supported as a texture."));
+ return false;
+ }
+
+ return true;
+}
+
+bool ValidateEGLImageTargetRenderbufferStorageOES(Context *context,
+ egl::Display *display,
+ GLenum target,
+ egl::Image *image)
+{
+ if (!context->getExtensions().eglImage)
+ {
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
+ }
+
+ switch (target)
+ {
+ case GL_RENDERBUFFER:
+ break;
+
+ default:
+ context->recordError(Error(GL_INVALID_ENUM, "invalid renderbuffer target."));
+ return false;
+ }
+
+ if (!display->isValidImage(image))
+ {
+ context->recordError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
+ return false;
+ }
+
+ const TextureCaps &textureCaps = context->getTextureCaps().get(image->getInternalFormat());
+ if (!textureCaps.renderable)
+ {
+ context->recordError(Error(
+ GL_INVALID_OPERATION, "EGL image internal format is not supported as a renderbuffer."));
+ return false;
+ }
+
+ return true;
+}
+
+bool ValidateBindVertexArrayBase(Context *context, GLuint array)
+{
+ if (!context->isVertexArrayGenerated(array))
+ {
+ // The default VAO should always exist
+ ASSERT(array != 0);
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
+ }
+
+ return true;
+}
+
+bool ValidateDeleteVertexArraysBase(Context *context, GLsizei n)
+{
+ if (n < 0)
+ {
+ context->recordError(Error(GL_INVALID_VALUE));
+ return false;
+ }
+
+ return true;
+}
+
+bool ValidateGenVertexArraysBase(Context *context, GLsizei n)
+{
+ if (n < 0)
+ {
+ context->recordError(Error(GL_INVALID_VALUE));
+ return false;
+ }
+
+ return true;
+}
+
+bool ValidateProgramBinaryBase(Context *context,
+ GLuint program,
+ GLenum binaryFormat,
+ const void *binary,
+ GLint length)
+{
+ Program *programObject = GetValidProgram(context, program);
+ if (programObject == nullptr)
+ {
+ return false;
+ }
+
+ const std::vector<GLenum> &programBinaryFormats = context->getCaps().programBinaryFormats;
+ if (std::find(programBinaryFormats.begin(), programBinaryFormats.end(), binaryFormat) ==
+ programBinaryFormats.end())
+ {
+ context->recordError(Error(GL_INVALID_ENUM, "Program binary format is not valid."));
+ return false;
+ }
+
+ return true;
+}
+
+bool ValidateGetProgramBinaryBase(Context *context,
+ GLuint program,
+ GLsizei bufSize,
+ GLsizei *length,
+ GLenum *binaryFormat,
+ void *binary)
+{
+ Program *programObject = GetValidProgram(context, program);
+ if (programObject == nullptr)
+ {
+ return false;
+ }
+
+ if (!programObject->isLinked())
+ {
+ context->recordError(Error(GL_INVALID_OPERATION, "Program is not linked."));
+ return false;
+ }
+
+ return true;
+}
+
+bool ValidateCopyTexImage2D(ValidationContext *context,
+ GLenum target,
+ GLint level,
+ GLenum internalformat,
+ GLint x,
+ GLint y,
+ GLsizei width,
+ GLsizei height,
+ GLint border)
+{
+ if (context->getClientVersion() < 3)
+ {
+ return ValidateES2CopyTexImageParameters(context, target, level, internalformat, false, 0,
+ 0, x, y, width, height, border);
+ }
+
+ ASSERT(context->getClientVersion() == 3);
+ return ValidateES3CopyTexImage2DParameters(context, target, level, internalformat, false, 0, 0,
+ 0, x, y, width, height, border);
+}
+
+bool ValidateFramebufferRenderbuffer(Context *context,
+ GLenum target,
+ GLenum attachment,
+ GLenum renderbuffertarget,
+ GLuint renderbuffer)
+{
+ if (!ValidFramebufferTarget(target) ||
+ (renderbuffertarget != GL_RENDERBUFFER && renderbuffer != 0))
+ {
+ context->recordError(Error(GL_INVALID_ENUM));
+ return false;
+ }
+
+ return ValidateFramebufferRenderbufferParameters(context, target, attachment,
+ renderbuffertarget, renderbuffer);
+}
+
+bool ValidateDrawBuffersBase(ValidationContext *context, GLsizei n, const GLenum *bufs)
+{
+ // INVALID_VALUE is generated if n is negative or greater than value of MAX_DRAW_BUFFERS
+ if (n < 0 || static_cast<GLuint>(n) > context->getCaps().maxDrawBuffers)
+ {
+ context->recordError(
+ Error(GL_INVALID_VALUE, "n must be non-negative and no greater than MAX_DRAW_BUFFERS"));
+ return false;
+ }
+
+ ASSERT(context->getState().getDrawFramebuffer());
+ GLuint frameBufferId = context->getState().getDrawFramebuffer()->id();
+ GLuint maxColorAttachment = GL_COLOR_ATTACHMENT0_EXT + context->getCaps().maxColorAttachments;
+
+ // This should come first before the check for the default frame buffer
+ // because when we switch to ES3.1+, invalid enums will return INVALID_ENUM
+ // rather than INVALID_OPERATION
+ for (int colorAttachment = 0; colorAttachment < n; colorAttachment++)
+ {
+ const GLenum attachment = GL_COLOR_ATTACHMENT0_EXT + colorAttachment;
+
+ if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != GL_BACK &&
+ (bufs[colorAttachment] < GL_COLOR_ATTACHMENT0_EXT ||
+ bufs[colorAttachment] >= maxColorAttachment))
+ {
+ // Value in bufs is not NONE, BACK, or GL_COLOR_ATTACHMENTi
+ // In the 3.0 specs, the error should return GL_INVALID_OPERATION.
+ // When we move to 3.1 specs, we should change the error to be GL_INVALID_ENUM
+ context->recordError(Error(GL_INVALID_OPERATION, "Invalid buffer value"));
+ return false;
+ }
+ else if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != attachment &&
+ frameBufferId != 0)
+ {
+ // INVALID_OPERATION-GL is bound to buffer and ith argument
+ // is not COLOR_ATTACHMENTi or NONE
+ context->recordError(
+ Error(GL_INVALID_OPERATION, "Ith value does not match COLOR_ATTACHMENTi or NONE"));
+ return false;
+ }
+ }
+
+ // INVALID_OPERATION is generated if GL is bound to the default framebuffer
+ // and n is not 1 or bufs is bound to value other than BACK and NONE
+ if (frameBufferId == 0)
+ {
+ if (n != 1)
+ {
+ context->recordError(Error(GL_INVALID_OPERATION,
+ "n must be 1 when GL is bound to the default framebuffer"));
+ return false;
+ }
+
+ if (bufs[0] != GL_NONE && bufs[0] != GL_BACK)
+ {
+ context->recordError(Error(
+ GL_INVALID_OPERATION,
+ "Only NONE or BACK are valid values when drawing to the default framebuffer"));
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool ValidateCopyTexSubImage2D(Context *context,
+ GLenum target,
+ GLint level,
+ GLint xoffset,
+ GLint yoffset,
+ GLint x,
+ GLint y,
+ GLsizei width,
+ GLsizei height)
+{
+ if (context->getClientVersion() < 3)
+ {
+ return ValidateES2CopyTexImageParameters(context, target, level, GL_NONE, true, xoffset,
+ yoffset, x, y, width, height, 0);
+ }
+
+ return ValidateES3CopyTexImage2DParameters(context, target, level, GL_NONE, true, xoffset,
+ yoffset, 0, x, y, width, height, 0);
+}
+
+} // namespace gl
diff --git a/src/3rdparty/angle/src/libANGLE/validationES.h b/src/3rdparty/angle/src/libANGLE/validationES.h
index b0ccd8eecc..5d8486a6ab 100644
--- a/src/3rdparty/angle/src/libANGLE/validationES.h
+++ b/src/3rdparty/angle/src/libANGLE/validationES.h
@@ -14,22 +14,51 @@
#include <GLES2/gl2.h>
#include <GLES3/gl3.h>
-namespace gl
+namespace egl
{
+class Display;
+class Image;
+}
+namespace gl
+{
class Context;
+class Program;
+class Shader;
+class ValidationContext;
bool ValidCap(const Context *context, GLenum cap);
-bool ValidTextureTarget(const Context *context, GLenum target);
-bool ValidTexture2DDestinationTarget(const Context *context, GLenum target);
+bool ValidTextureTarget(const ValidationContext *context, GLenum target);
+bool ValidTexture2DTarget(const ValidationContext *context, GLenum target);
+bool ValidTexture3DTarget(const ValidationContext *context, GLenum target);
+bool ValidTexture2DDestinationTarget(const ValidationContext *context, GLenum target);
+bool ValidTexture3DDestinationTarget(const ValidationContext *context, GLenum target);
bool ValidFramebufferTarget(GLenum target);
bool ValidBufferTarget(const Context *context, GLenum target);
bool ValidBufferParameter(const Context *context, GLenum pname);
-bool ValidMipLevel(const Context *context, GLenum target, GLint level);
-bool ValidImageSize(const Context *context, GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth);
-bool ValidCompressedImageSize(const Context *context, GLenum internalFormat, GLsizei width, GLsizei height);
+bool ValidMipLevel(const ValidationContext *context, GLenum target, GLint level);
+bool ValidImageSizeParameters(const Context *context,
+ GLenum target,
+ GLint level,
+ GLsizei width,
+ GLsizei height,
+ GLsizei depth,
+ bool isSubImage);
+bool ValidCompressedImageSize(const ValidationContext *context,
+ GLenum internalFormat,
+ GLsizei width,
+ GLsizei height);
bool ValidQueryType(const Context *context, GLenum queryType);
-bool ValidProgram(Context *context, GLuint id);
+
+// Returns valid program if id is a valid program name
+// Errors INVALID_OPERATION if valid shader is given and returns NULL
+// Errors INVALID_VALUE otherwise and returns NULL
+Program *GetValidProgram(Context *context, GLuint id);
+
+// Returns valid shader if id is a valid shader name
+// Errors INVALID_OPERATION if valid program is given and returns NULL
+// Errors INVALID_VALUE otherwise and returns NULL
+Shader *GetValidShader(Context *context, GLuint id);
bool ValidateAttachmentTarget(Context *context, GLenum attachment);
bool ValidateRenderbufferStorageParametersBase(Context *context, GLenum target, GLsizei samples,
@@ -40,9 +69,17 @@ bool ValidateRenderbufferStorageParametersANGLE(Context *context, GLenum target,
bool ValidateFramebufferRenderbufferParameters(Context *context, GLenum target, GLenum attachment,
GLenum renderbuffertarget, GLuint renderbuffer);
-bool ValidateBlitFramebufferParameters(Context *context, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
- GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask,
- GLenum filter, bool fromAngleExtension);
+bool ValidateBlitFramebufferParameters(Context *context,
+ GLint srcX0,
+ GLint srcY0,
+ GLint srcX1,
+ GLint srcY1,
+ GLint dstX0,
+ GLint dstY0,
+ GLint dstX1,
+ GLint dstY1,
+ GLbitfield mask,
+ GLenum filter);
bool ValidateGetVertexAttribParameters(Context *context, GLenum pname);
@@ -50,11 +87,40 @@ bool ValidateTexParamParameters(Context *context, GLenum pname, GLint param);
bool ValidateSamplerObjectParameter(Context *context, GLenum pname);
-bool ValidateReadPixelsParameters(Context *context, GLint x, GLint y, GLsizei width, GLsizei height,
- GLenum format, GLenum type, GLsizei *bufSize, GLvoid *pixels);
-
-bool ValidateBeginQuery(Context *context, GLenum target, GLuint id);
-bool ValidateEndQuery(Context *context, GLenum target);
+bool ValidateReadPixels(Context *context,
+ GLint x,
+ GLint y,
+ GLsizei width,
+ GLsizei height,
+ GLenum format,
+ GLenum type,
+ GLvoid *pixels);
+bool ValidateReadnPixelsEXT(Context *context,
+ GLint x,
+ GLint y,
+ GLsizei width,
+ GLsizei height,
+ GLenum format,
+ GLenum type,
+ GLsizei bufSize,
+ GLvoid *pixels);
+
+bool ValidateGenQueriesBase(gl::Context *context, GLsizei n, const GLuint *ids);
+bool ValidateGenQueriesEXT(gl::Context *context, GLsizei n, const GLuint *ids);
+bool ValidateDeleteQueriesBase(gl::Context *context, GLsizei n, const GLuint *ids);
+bool ValidateDeleteQueriesEXT(gl::Context *context, GLsizei n, const GLuint *ids);
+bool ValidateBeginQueryBase(Context *context, GLenum target, GLuint id);
+bool ValidateBeginQueryEXT(Context *context, GLenum target, GLuint id);
+bool ValidateEndQueryBase(Context *context, GLenum target);
+bool ValidateEndQueryEXT(Context *context, GLenum target);
+bool ValidateQueryCounterEXT(Context *context, GLuint id, GLenum target);
+bool ValidateGetQueryivBase(Context *context, GLenum target, GLenum pname);
+bool ValidateGetQueryivEXT(Context *context, GLenum target, GLenum pname, GLint *params);
+bool ValidateGetQueryObjectValueBase(Context *context, GLenum target, GLenum pname);
+bool ValidateGetQueryObjectivEXT(Context *context, GLuint id, GLenum pname, GLint *params);
+bool ValidateGetQueryObjectuivEXT(Context *context, GLuint id, GLenum pname, GLuint *params);
+bool ValidateGetQueryObjecti64vEXT(Context *context, GLuint id, GLenum pname, GLint64 *params);
+bool ValidateGetQueryObjectui64vEXT(Context *context, GLuint id, GLenum pname, GLuint64 *params);
bool ValidateUniform(Context *context, GLenum uniformType, GLint location, GLsizei count);
bool ValidateUniformMatrix(Context *context, GLenum matrixType, GLint location, GLsizei count,
@@ -62,26 +128,57 @@ bool ValidateUniformMatrix(Context *context, GLenum matrixType, GLint location,
bool ValidateStateQuery(Context *context, GLenum pname, GLenum *nativeType, unsigned int *numParams);
-bool ValidateCopyTexImageParametersBase(Context* context, GLenum target, GLint level, GLenum internalformat, bool isSubImage,
- GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height,
- GLint border, GLenum *textureInternalFormatOut);
+bool ValidateCopyTexImageParametersBase(ValidationContext *context,
+ GLenum target,
+ GLint level,
+ GLenum internalformat,
+ bool isSubImage,
+ GLint xoffset,
+ GLint yoffset,
+ GLint zoffset,
+ GLint x,
+ GLint y,
+ GLsizei width,
+ GLsizei height,
+ GLint border,
+ GLenum *textureInternalFormatOut);
bool ValidateDrawArrays(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount);
bool ValidateDrawArraysInstanced(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount);
bool ValidateDrawArraysInstancedANGLE(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount);
-bool ValidateDrawElements(Context *context, GLenum mode, GLsizei count, GLenum type,
- const GLvoid* indices, GLsizei primcount, rx::RangeUI *indexRangeOut);
-
-bool ValidateDrawElementsInstanced(Context *context, GLenum mode, GLsizei count, GLenum type,
- const GLvoid *indices, GLsizei primcount, rx::RangeUI *indexRangeOut);
-bool ValidateDrawElementsInstancedANGLE(Context *context, GLenum mode, GLsizei count, GLenum type,
- const GLvoid *indices, GLsizei primcount, rx::RangeUI *indexRangeOut);
+bool ValidateDrawElements(ValidationContext *context,
+ GLenum mode,
+ GLsizei count,
+ GLenum type,
+ const GLvoid *indices,
+ GLsizei primcount,
+ IndexRange *indexRangeOut);
+
+bool ValidateDrawElementsInstanced(Context *context,
+ GLenum mode,
+ GLsizei count,
+ GLenum type,
+ const GLvoid *indices,
+ GLsizei primcount,
+ IndexRange *indexRangeOut);
+bool ValidateDrawElementsInstancedANGLE(Context *context,
+ GLenum mode,
+ GLsizei count,
+ GLenum type,
+ const GLvoid *indices,
+ GLsizei primcount,
+ IndexRange *indexRangeOut);
bool ValidateFramebufferTextureBase(Context *context, GLenum target, GLenum attachment,
GLuint texture, GLint level);
bool ValidateFramebufferTexture2D(Context *context, GLenum target, GLenum attachment,
GLenum textarget, GLuint texture, GLint level);
+bool ValidateFramebufferRenderbuffer(Context *context,
+ GLenum target,
+ GLenum attachment,
+ GLenum renderbuffertarget,
+ GLuint renderbuffer);
bool ValidateGetUniformBase(Context *context, GLuint program, GLint location);
bool ValidateGetUniformfv(Context *context, GLuint program, GLint location, GLfloat* params);
@@ -89,6 +186,59 @@ bool ValidateGetUniformiv(Context *context, GLuint program, GLint location, GLin
bool ValidateGetnUniformfvEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLfloat* params);
bool ValidateGetnUniformivEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLint* params);
-}
+bool ValidateDiscardFramebufferBase(Context *context, GLenum target, GLsizei numAttachments,
+ const GLenum *attachments, bool defaultFramebuffer);
+
+bool ValidateInsertEventMarkerEXT(Context *context, GLsizei length, const char *marker);
+bool ValidatePushGroupMarkerEXT(Context *context, GLsizei length, const char *marker);
+
+bool ValidateEGLImageTargetTexture2DOES(Context *context,
+ egl::Display *display,
+ GLenum target,
+ egl::Image *image);
+bool ValidateEGLImageTargetRenderbufferStorageOES(Context *context,
+ egl::Display *display,
+ GLenum target,
+ egl::Image *image);
+
+bool ValidateBindVertexArrayBase(Context *context, GLuint array);
+bool ValidateDeleteVertexArraysBase(Context *context, GLsizei n);
+bool ValidateGenVertexArraysBase(Context *context, GLsizei n);
+
+bool ValidateProgramBinaryBase(Context *context,
+ GLuint program,
+ GLenum binaryFormat,
+ const void *binary,
+ GLint length);
+bool ValidateGetProgramBinaryBase(Context *context,
+ GLuint program,
+ GLsizei bufSize,
+ GLsizei *length,
+ GLenum *binaryFormat,
+ void *binary);
+
+bool ValidateCopyTexImage2D(ValidationContext *context,
+ GLenum target,
+ GLint level,
+ GLenum internalformat,
+ GLint x,
+ GLint y,
+ GLsizei width,
+ GLsizei height,
+ GLint border);
+bool ValidateDrawBuffersBase(ValidationContext *context, GLsizei n, const GLenum *bufs);
+bool ValidateCopyTexSubImage2D(Context *context,
+ GLenum target,
+ GLint level,
+ GLint xoffset,
+ GLint yoffset,
+ GLint x,
+ GLint y,
+ GLsizei width,
+ GLsizei height);
+
+// Error messages shared here for use in testing.
+extern const char *g_ExceedsMaxElementErrorMessage;
+} // namespace gl
#endif // LIBANGLE_VALIDATION_ES_H_
diff --git a/src/3rdparty/angle/src/libANGLE/validationES2.cpp b/src/3rdparty/angle/src/libANGLE/validationES2.cpp
index 9eece1b54a..2e5b955e99 100644
--- a/src/3rdparty/angle/src/libANGLE/validationES2.cpp
+++ b/src/3rdparty/angle/src/libANGLE/validationES2.cpp
@@ -21,6 +21,42 @@
namespace gl
{
+namespace
+{
+
+bool IsPartialBlit(gl::Context *context,
+ const FramebufferAttachment *readBuffer,
+ const FramebufferAttachment *writeBuffer,
+ GLint srcX0,
+ GLint srcY0,
+ GLint srcX1,
+ GLint srcY1,
+ GLint dstX0,
+ GLint dstY0,
+ GLint dstX1,
+ GLint dstY1)
+{
+ const Extents &writeSize = writeBuffer->getSize();
+ const Extents &readSize = readBuffer->getSize();
+
+ if (srcX0 != 0 || srcY0 != 0 || dstX0 != 0 || dstY0 != 0 || dstX1 != writeSize.width ||
+ dstY1 != writeSize.height || srcX1 != readSize.width || srcY1 != readSize.height)
+ {
+ return true;
+ }
+
+ if (context->getState().isScissorTestEnabled())
+ {
+ const Rectangle &scissor = context->getState().getScissor();
+ return scissor.x > 0 || scissor.y > 0 || scissor.width < writeSize.width ||
+ scissor.height < writeSize.height;
+ }
+
+ return false;
+}
+
+} // anonymous namespace
+
bool ValidateES2TexImageParameters(Context *context, GLenum target, GLint level, GLenum internalformat, bool isCompressed, bool isSubImage,
GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
GLint border, GLenum format, GLenum type, const GLvoid *pixels)
@@ -31,7 +67,7 @@ bool ValidateES2TexImageParameters(Context *context, GLenum target, GLint level,
return false;
}
- if (!ValidImageSize(context, target, level, width, height, 1))
+ if (!ValidImageSizeParameters(context, target, level, width, height, 1, isSubImage))
{
context->recordError(Error(GL_INVALID_VALUE));
return false;
@@ -110,7 +146,7 @@ bool ValidateES2TexImageParameters(Context *context, GLenum target, GLint level,
}
else
{
- if (texture->isImmutable())
+ if (texture->getImmutableFormat())
{
context->recordError(Error(GL_INVALID_OPERATION));
return false;
@@ -124,23 +160,10 @@ bool ValidateES2TexImageParameters(Context *context, GLenum target, GLint level,
return false;
}
- GLenum actualInternalFormat = isSubImage ? texture->getInternalFormat(target, level) : internalformat;
- const InternalFormat &actualFormatInfo = GetInternalFormatInfo(actualInternalFormat);
-
- if (isCompressed != actualFormatInfo.compressed)
- {
- context->recordError(Error(GL_INVALID_OPERATION));
- return false;
- }
-
if (isCompressed)
{
- if (!ValidCompressedImageSize(context, actualInternalFormat, width, height))
- {
- context->recordError(Error(GL_INVALID_OPERATION));
- return false;
- }
-
+ GLenum actualInternalFormat =
+ isSubImage ? texture->getInternalFormat(target, level) : internalformat;
switch (actualInternalFormat)
{
case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
@@ -165,8 +188,29 @@ bool ValidateES2TexImageParameters(Context *context, GLenum target, GLint level,
return false;
}
break;
+ case GL_ETC1_RGB8_OES:
+ if (!context->getExtensions().compressedETC1RGB8Texture)
+ {
+ context->recordError(Error(GL_INVALID_ENUM));
+ return false;
+ }
+ break;
+ case GL_ETC1_RGB8_LOSSY_DECODE_ANGLE:
+ if (!context->getExtensions().lossyETCDecode)
+ {
+ context->recordError(
+ Error(GL_INVALID_ENUM, "ANGLE_lossy_etc_decode extension is not supported"));
+ return false;
+ }
+ break;
default:
- context->recordError(Error(GL_INVALID_ENUM));
+ context->recordError(Error(
+ GL_INVALID_ENUM, "internalformat is not a supported compressed internal format"));
+ return false;
+ }
+ if (!ValidCompressedImageSize(context, actualInternalFormat, width, height))
+ {
+ context->recordError(Error(GL_INVALID_OPERATION));
return false;
}
}
@@ -350,6 +394,33 @@ bool ValidateES2TexImageParameters(Context *context, GLenum target, GLint level,
return false;
}
break;
+ case GL_ETC1_RGB8_OES:
+ if (context->getExtensions().compressedETC1RGB8Texture)
+ {
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
+ }
+ else
+ {
+ context->recordError(Error(GL_INVALID_ENUM));
+ return false;
+ }
+ break;
+ case GL_ETC1_RGB8_LOSSY_DECODE_ANGLE:
+ if (context->getExtensions().lossyETCDecode)
+ {
+ context->recordError(
+ Error(GL_INVALID_OPERATION,
+ "ETC1_RGB8_LOSSY_DECODE_ANGLE can't work with this type."));
+ return false;
+ }
+ else
+ {
+ context->recordError(
+ Error(GL_INVALID_ENUM, "ANGLE_lossy_etc_decode extension is not supported."));
+ return false;
+ }
+ break;
case GL_DEPTH_COMPONENT:
case GL_DEPTH_STENCIL_OES:
if (!context->getExtensions().depthTextures)
@@ -395,21 +466,34 @@ bool ValidateES2TexImageParameters(Context *context, GLenum target, GLint level,
return true;
}
-
-
-bool ValidateES2CopyTexImageParameters(Context* context, GLenum target, GLint level, GLenum internalformat, bool isSubImage,
- GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height,
+bool ValidateES2CopyTexImageParameters(ValidationContext *context,
+ GLenum target,
+ GLint level,
+ GLenum internalformat,
+ bool isSubImage,
+ GLint xoffset,
+ GLint yoffset,
+ GLint x,
+ GLint y,
+ GLsizei width,
+ GLsizei height,
GLint border)
{
GLenum textureInternalFormat = GL_NONE;
+ if (!ValidTexture2DDestinationTarget(context, target))
+ {
+ context->recordError(Error(GL_INVALID_ENUM, "Invalid texture target"));
+ return false;
+ }
+
if (!ValidateCopyTexImageParametersBase(context, target, level, internalformat, isSubImage,
xoffset, yoffset, 0, x, y, width, height, border, &textureInternalFormat))
{
return false;
}
- gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
+ const gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
GLenum colorbufferFormat = framebuffer->getReadColorbuffer()->getInternalFormat();
const auto &internalFormatInfo = gl::GetInternalFormatInfo(textureInternalFormat);
GLenum textureFormat = internalFormatInfo.format;
@@ -502,6 +586,8 @@ bool ValidateES2CopyTexImageParameters(Context* context, GLenum target, GLint le
case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
+ case GL_ETC1_RGB8_OES:
+ case GL_ETC1_RGB8_LOSSY_DECODE_ANGLE:
context->recordError(Error(GL_INVALID_OPERATION));
return false;
case GL_DEPTH_COMPONENT:
@@ -642,6 +728,32 @@ bool ValidateES2CopyTexImageParameters(Context* context, GLenum target, GLint le
return false;
}
break;
+ case GL_ETC1_RGB8_OES:
+ if (context->getExtensions().compressedETC1RGB8Texture)
+ {
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
+ }
+ else
+ {
+ context->recordError(Error(GL_INVALID_ENUM));
+ return false;
+ }
+ break;
+ case GL_ETC1_RGB8_LOSSY_DECODE_ANGLE:
+ if (context->getExtensions().lossyETCDecode)
+ {
+ context->recordError(Error(GL_INVALID_OPERATION,
+ "ETC1_RGB8_LOSSY_DECODE_ANGLE can't be copied to."));
+ return false;
+ }
+ else
+ {
+ context->recordError(
+ Error(GL_INVALID_ENUM, "ANGLE_lossy_etc_decode extension is not supported."));
+ return false;
+ }
+ break;
case GL_DEPTH_COMPONENT:
case GL_DEPTH_COMPONENT16:
case GL_DEPTH_COMPONENT32_OES:
@@ -759,6 +871,21 @@ bool ValidateES2TexStorageParameters(Context *context, GLenum target, GLsizei le
return false;
}
break;
+ case GL_ETC1_RGB8_OES:
+ if (!context->getExtensions().compressedETC1RGB8Texture)
+ {
+ context->recordError(Error(GL_INVALID_ENUM));
+ return false;
+ }
+ break;
+ case GL_ETC1_RGB8_LOSSY_DECODE_ANGLE:
+ if (!context->getExtensions().lossyETCDecode)
+ {
+ context->recordError(
+ Error(GL_INVALID_ENUM, "ANGLE_lossy_etc_decode extension is not supported."));
+ return false;
+ }
+ break;
case GL_RGBA32F_EXT:
case GL_RGB32F_EXT:
case GL_ALPHA32F_EXT:
@@ -824,7 +951,7 @@ bool ValidateES2TexStorageParameters(Context *context, GLenum target, GLsizei le
return false;
}
- if (texture->isImmutable())
+ if (texture->getImmutableFormat())
{
context->recordError(Error(GL_INVALID_OPERATION));
return false;
@@ -879,4 +1006,751 @@ bool ValidES2ReadFormatType(Context *context, GLenum format, GLenum type)
return true;
}
+bool ValidateDiscardFramebufferEXT(Context *context, GLenum target, GLsizei numAttachments,
+ const GLenum *attachments)
+{
+ if (!context->getExtensions().discardFramebuffer)
+ {
+ context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled"));
+ return false;
+ }
+
+ bool defaultFramebuffer = false;
+
+ switch (target)
+ {
+ case GL_FRAMEBUFFER:
+ defaultFramebuffer = (context->getState().getTargetFramebuffer(GL_FRAMEBUFFER)->id() == 0);
+ break;
+ default:
+ context->recordError(Error(GL_INVALID_ENUM, "Invalid framebuffer target"));
+ return false;
+ }
+
+ return ValidateDiscardFramebufferBase(context, target, numAttachments, attachments, defaultFramebuffer);
+}
+
+bool ValidateBindVertexArrayOES(Context *context, GLuint array)
+{
+ if (!context->getExtensions().vertexArrayObject)
+ {
+ context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled"));
+ return false;
+ }
+
+ return ValidateBindVertexArrayBase(context, array);
+}
+
+bool ValidateDeleteVertexArraysOES(Context *context, GLsizei n)
+{
+ if (!context->getExtensions().vertexArrayObject)
+ {
+ context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled"));
+ return false;
+ }
+
+ return ValidateDeleteVertexArraysBase(context, n);
+}
+
+bool ValidateGenVertexArraysOES(Context *context, GLsizei n)
+{
+ if (!context->getExtensions().vertexArrayObject)
+ {
+ context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled"));
+ return false;
+ }
+
+ return ValidateGenVertexArraysBase(context, n);
+}
+
+bool ValidateIsVertexArrayOES(Context *context)
+{
+ if (!context->getExtensions().vertexArrayObject)
+ {
+ context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled"));
+ return false;
+ }
+
+ return true;
+}
+
+bool ValidateProgramBinaryOES(Context *context,
+ GLuint program,
+ GLenum binaryFormat,
+ const void *binary,
+ GLint length)
+{
+ if (!context->getExtensions().getProgramBinary)
+ {
+ context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled"));
+ return false;
+ }
+
+ return ValidateProgramBinaryBase(context, program, binaryFormat, binary, length);
+}
+
+bool ValidateGetProgramBinaryOES(Context *context,
+ GLuint program,
+ GLsizei bufSize,
+ GLsizei *length,
+ GLenum *binaryFormat,
+ void *binary)
+{
+ if (!context->getExtensions().getProgramBinary)
+ {
+ context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled"));
+ return false;
+ }
+
+ return ValidateGetProgramBinaryBase(context, program, bufSize, length, binaryFormat, binary);
+}
+
+static bool ValidDebugSource(GLenum source, bool mustBeThirdPartyOrApplication)
+{
+ switch (source)
+ {
+ case GL_DEBUG_SOURCE_API:
+ case GL_DEBUG_SOURCE_SHADER_COMPILER:
+ case GL_DEBUG_SOURCE_WINDOW_SYSTEM:
+ case GL_DEBUG_SOURCE_OTHER:
+ // Only THIRD_PARTY and APPLICATION sources are allowed to be manually inserted
+ return !mustBeThirdPartyOrApplication;
+
+ case GL_DEBUG_SOURCE_THIRD_PARTY:
+ case GL_DEBUG_SOURCE_APPLICATION:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+static bool ValidDebugType(GLenum type)
+{
+ switch (type)
+ {
+ case GL_DEBUG_TYPE_ERROR:
+ case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR:
+ case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR:
+ case GL_DEBUG_TYPE_PERFORMANCE:
+ case GL_DEBUG_TYPE_PORTABILITY:
+ case GL_DEBUG_TYPE_OTHER:
+ case GL_DEBUG_TYPE_MARKER:
+ case GL_DEBUG_TYPE_PUSH_GROUP:
+ case GL_DEBUG_TYPE_POP_GROUP:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+static bool ValidDebugSeverity(GLenum severity)
+{
+ switch (severity)
+ {
+ case GL_DEBUG_SEVERITY_HIGH:
+ case GL_DEBUG_SEVERITY_MEDIUM:
+ case GL_DEBUG_SEVERITY_LOW:
+ case GL_DEBUG_SEVERITY_NOTIFICATION:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+bool ValidateDebugMessageControlKHR(Context *context,
+ GLenum source,
+ GLenum type,
+ GLenum severity,
+ GLsizei count,
+ const GLuint *ids,
+ GLboolean enabled)
+{
+ if (!context->getExtensions().debug)
+ {
+ context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled"));
+ return false;
+ }
+
+ if (!ValidDebugSource(source, false) && source != GL_DONT_CARE)
+ {
+ context->recordError(Error(GL_INVALID_ENUM, "Invalid debug source."));
+ return false;
+ }
+
+ if (!ValidDebugType(type) && type != GL_DONT_CARE)
+ {
+ context->recordError(Error(GL_INVALID_ENUM, "Invalid debug type."));
+ return false;
+ }
+
+ if (!ValidDebugSeverity(severity) && severity != GL_DONT_CARE)
+ {
+ context->recordError(Error(GL_INVALID_ENUM, "Invalid debug severity."));
+ return false;
+ }
+
+ if (count > 0)
+ {
+ if (source == GL_DONT_CARE || type == GL_DONT_CARE)
+ {
+ context->recordError(Error(
+ GL_INVALID_OPERATION,
+ "If count is greater than zero, source and severity cannot be GL_DONT_CARE."));
+ return false;
+ }
+
+ if (severity != GL_DONT_CARE)
+ {
+ context->recordError(
+ Error(GL_INVALID_OPERATION,
+ "If count is greater than zero, severity must be GL_DONT_CARE."));
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool ValidateDebugMessageInsertKHR(Context *context,
+ GLenum source,
+ GLenum type,
+ GLuint id,
+ GLenum severity,
+ GLsizei length,
+ const GLchar *buf)
+{
+ if (!context->getExtensions().debug)
+ {
+ context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled"));
+ return false;
+ }
+
+ if (!context->getState().getDebug().isOutputEnabled())
+ {
+ // If the DEBUG_OUTPUT state is disabled calls to DebugMessageInsert are discarded and do
+ // not generate an error.
+ return false;
+ }
+
+ if (!ValidDebugSeverity(severity))
+ {
+ context->recordError(Error(GL_INVALID_ENUM, "Invalid debug severity."));
+ return false;
+ }
+
+ if (!ValidDebugType(type))
+ {
+ context->recordError(Error(GL_INVALID_ENUM, "Invalid debug type."));
+ return false;
+ }
+
+ if (!ValidDebugSource(source, true))
+ {
+ context->recordError(Error(GL_INVALID_ENUM, "Invalid debug source."));
+ return false;
+ }
+
+ size_t messageLength = (length < 0) ? strlen(buf) : length;
+ if (messageLength > context->getExtensions().maxDebugMessageLength)
+ {
+ context->recordError(
+ Error(GL_INVALID_VALUE, "Message length is larger than GL_MAX_DEBUG_MESSAGE_LENGTH."));
+ return false;
+ }
+
+ return true;
+}
+
+bool ValidateDebugMessageCallbackKHR(Context *context,
+ GLDEBUGPROCKHR callback,
+ const void *userParam)
+{
+ if (!context->getExtensions().debug)
+ {
+ context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled"));
+ return false;
+ }
+
+ return true;
+}
+
+bool ValidateGetDebugMessageLogKHR(Context *context,
+ GLuint count,
+ GLsizei bufSize,
+ GLenum *sources,
+ GLenum *types,
+ GLuint *ids,
+ GLenum *severities,
+ GLsizei *lengths,
+ GLchar *messageLog)
+{
+ if (!context->getExtensions().debug)
+ {
+ context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled"));
+ return false;
+ }
+
+ if (bufSize < 0 && messageLog != nullptr)
+ {
+ context->recordError(
+ Error(GL_INVALID_VALUE, "bufSize must be positive if messageLog is not null."));
+ return false;
+ }
+
+ return true;
+}
+
+bool ValidatePushDebugGroupKHR(Context *context,
+ GLenum source,
+ GLuint id,
+ GLsizei length,
+ const GLchar *message)
+{
+ if (!context->getExtensions().debug)
+ {
+ context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled"));
+ return false;
+ }
+
+ if (!ValidDebugSource(source, true))
+ {
+ context->recordError(Error(GL_INVALID_ENUM, "Invalid debug source."));
+ return false;
+ }
+
+ size_t messageLength = (length < 0) ? strlen(message) : length;
+ if (messageLength > context->getExtensions().maxDebugMessageLength)
+ {
+ context->recordError(
+ Error(GL_INVALID_VALUE, "Message length is larger than GL_MAX_DEBUG_MESSAGE_LENGTH."));
+ return false;
+ }
+
+ size_t currentStackSize = context->getState().getDebug().getGroupStackDepth();
+ if (currentStackSize >= context->getExtensions().maxDebugGroupStackDepth)
+ {
+ context->recordError(
+ Error(GL_STACK_OVERFLOW,
+ "Cannot push more than GL_MAX_DEBUG_GROUP_STACK_DEPTH debug groups."));
+ return false;
+ }
+
+ return true;
+}
+
+bool ValidatePopDebugGroupKHR(Context *context)
+{
+ if (!context->getExtensions().debug)
+ {
+ context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled"));
+ return false;
+ }
+
+ size_t currentStackSize = context->getState().getDebug().getGroupStackDepth();
+ if (currentStackSize <= 1)
+ {
+ context->recordError(Error(GL_STACK_UNDERFLOW, "Cannot pop the default debug group."));
+ return false;
+ }
+
+ return true;
+}
+
+static bool ValidateObjectIdentifierAndName(Context *context, GLenum identifier, GLuint name)
+{
+ switch (identifier)
+ {
+ case GL_BUFFER:
+ if (context->getBuffer(name) == nullptr)
+ {
+ context->recordError(Error(GL_INVALID_VALUE, "name is not a valid buffer."));
+ return false;
+ }
+ return true;
+
+ case GL_SHADER:
+ if (context->getShader(name) == nullptr)
+ {
+ context->recordError(Error(GL_INVALID_VALUE, "name is not a valid shader."));
+ return false;
+ }
+ return true;
+
+ case GL_PROGRAM:
+ if (context->getProgram(name) == nullptr)
+ {
+ context->recordError(Error(GL_INVALID_VALUE, "name is not a valid program."));
+ return false;
+ }
+ return true;
+
+ case GL_VERTEX_ARRAY:
+ if (context->getVertexArray(name) == nullptr)
+ {
+ context->recordError(Error(GL_INVALID_VALUE, "name is not a valid vertex array."));
+ return false;
+ }
+ return true;
+
+ case GL_QUERY:
+ if (context->getQuery(name) == nullptr)
+ {
+ context->recordError(Error(GL_INVALID_VALUE, "name is not a valid query."));
+ return false;
+ }
+ return true;
+
+ case GL_TRANSFORM_FEEDBACK:
+ if (context->getTransformFeedback(name) == nullptr)
+ {
+ context->recordError(
+ Error(GL_INVALID_VALUE, "name is not a valid transform feedback."));
+ return false;
+ }
+ return true;
+
+ case GL_SAMPLER:
+ if (context->getSampler(name) == nullptr)
+ {
+ context->recordError(Error(GL_INVALID_VALUE, "name is not a valid sampler."));
+ return false;
+ }
+ return true;
+
+ case GL_TEXTURE:
+ if (context->getTexture(name) == nullptr)
+ {
+ context->recordError(Error(GL_INVALID_VALUE, "name is not a valid texture."));
+ return false;
+ }
+ return true;
+
+ case GL_RENDERBUFFER:
+ if (context->getRenderbuffer(name) == nullptr)
+ {
+ context->recordError(Error(GL_INVALID_VALUE, "name is not a valid renderbuffer."));
+ return false;
+ }
+ return true;
+
+ case GL_FRAMEBUFFER:
+ if (context->getFramebuffer(name) == nullptr)
+ {
+ context->recordError(Error(GL_INVALID_VALUE, "name is not a valid framebuffer."));
+ return false;
+ }
+ return true;
+
+ default:
+ context->recordError(Error(GL_INVALID_ENUM, "Invalid identifier."));
+ return false;
+ }
+
+ return true;
+}
+
+bool ValidateObjectLabelKHR(Context *context,
+ GLenum identifier,
+ GLuint name,
+ GLsizei length,
+ const GLchar *label)
+{
+ if (!context->getExtensions().debug)
+ {
+ context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled"));
+ return false;
+ }
+
+ if (!ValidateObjectIdentifierAndName(context, identifier, name))
+ {
+ return false;
+ }
+
+ size_t labelLength = (length < 0) ? strlen(label) : length;
+ if (labelLength > context->getExtensions().maxLabelLength)
+ {
+ context->recordError(
+ Error(GL_INVALID_VALUE, "Label length is larger than GL_MAX_LABEL_LENGTH."));
+ return false;
+ }
+
+ return true;
+}
+
+bool ValidateGetObjectLabelKHR(Context *context,
+ GLenum identifier,
+ GLuint name,
+ GLsizei bufSize,
+ GLsizei *length,
+ GLchar *label)
+{
+ if (!context->getExtensions().debug)
+ {
+ context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled"));
+ return false;
+ }
+
+ if (bufSize < 0)
+ {
+ context->recordError(Error(GL_INVALID_VALUE, "bufSize cannot be negative."));
+ return false;
+ }
+
+ if (!ValidateObjectIdentifierAndName(context, identifier, name))
+ {
+ return false;
+ }
+
+ // Can no-op if bufSize is zero.
+ return bufSize > 0;
+}
+
+static bool ValidateObjectPtrName(Context *context, const void *ptr)
+{
+ if (context->getFenceSync(reinterpret_cast<GLsync>(const_cast<void *>(ptr))) == nullptr)
+ {
+ context->recordError(Error(GL_INVALID_VALUE, "name is not a valid sync."));
+ return false;
+ }
+
+ return true;
+}
+
+bool ValidateObjectPtrLabelKHR(Context *context,
+ const void *ptr,
+ GLsizei length,
+ const GLchar *label)
+{
+ if (!context->getExtensions().debug)
+ {
+ context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled"));
+ return false;
+ }
+
+ if (!ValidateObjectPtrName(context, ptr))
+ {
+ return false;
+ }
+
+ size_t labelLength = (length < 0) ? strlen(label) : length;
+ if (labelLength > context->getExtensions().maxLabelLength)
+ {
+ context->recordError(
+ Error(GL_INVALID_VALUE, "Label length is larger than GL_MAX_LABEL_LENGTH."));
+ return false;
+ }
+
+ return true;
+}
+
+bool ValidateGetObjectPtrLabelKHR(Context *context,
+ const void *ptr,
+ GLsizei bufSize,
+ GLsizei *length,
+ GLchar *label)
+{
+ if (!context->getExtensions().debug)
+ {
+ context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled"));
+ return false;
+ }
+
+ if (bufSize < 0)
+ {
+ context->recordError(Error(GL_INVALID_VALUE, "bufSize cannot be negative."));
+ return false;
+ }
+
+ if (!ValidateObjectPtrName(context, ptr))
+ {
+ return false;
+ }
+
+ // Can no-op if bufSize is zero.
+ return bufSize > 0;
+}
+
+bool ValidateGetPointervKHR(Context *context, GLenum pname, void **params)
+{
+ if (!context->getExtensions().debug)
+ {
+ context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled"));
+ return false;
+ }
+
+ // TODO: represent this in Context::getQueryParameterInfo.
+ switch (pname)
+ {
+ case GL_DEBUG_CALLBACK_FUNCTION:
+ case GL_DEBUG_CALLBACK_USER_PARAM:
+ break;
+
+ default:
+ context->recordError(Error(GL_INVALID_ENUM, "Invalid pname."));
+ return false;
+ }
+
+ return true;
+}
+
+bool ValidateBlitFramebufferANGLE(Context *context,
+ GLint srcX0,
+ GLint srcY0,
+ GLint srcX1,
+ GLint srcY1,
+ GLint dstX0,
+ GLint dstY0,
+ GLint dstX1,
+ GLint dstY1,
+ GLbitfield mask,
+ GLenum filter)
+{
+ if (!context->getExtensions().framebufferBlit)
+ {
+ context->recordError(Error(GL_INVALID_OPERATION, "Blit extension not available."));
+ return false;
+ }
+
+ if (srcX1 - srcX0 != dstX1 - dstX0 || srcY1 - srcY0 != dstY1 - dstY0)
+ {
+ // TODO(jmadill): Determine if this should be available on other implementations.
+ context->recordError(Error(
+ GL_INVALID_OPERATION,
+ "Scaling and flipping in BlitFramebufferANGLE not supported by this implementation."));
+ return false;
+ }
+
+ if (filter == GL_LINEAR)
+ {
+ context->recordError(Error(GL_INVALID_ENUM, "Linear blit not supported in this extension"));
+ return false;
+ }
+
+ const Framebuffer *readFramebuffer = context->getState().getReadFramebuffer();
+ const Framebuffer *drawFramebuffer = context->getState().getDrawFramebuffer();
+
+ if (mask & GL_COLOR_BUFFER_BIT)
+ {
+ const FramebufferAttachment *readColorAttachment = readFramebuffer->getReadColorbuffer();
+ const FramebufferAttachment *drawColorAttachment = drawFramebuffer->getFirstColorbuffer();
+
+ if (readColorAttachment && drawColorAttachment)
+ {
+ if (!(readColorAttachment->type() == GL_TEXTURE &&
+ readColorAttachment->getTextureImageIndex().type == GL_TEXTURE_2D) &&
+ readColorAttachment->type() != GL_RENDERBUFFER &&
+ readColorAttachment->type() != GL_FRAMEBUFFER_DEFAULT)
+ {
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
+ }
+
+ for (size_t drawbufferIdx = 0;
+ drawbufferIdx < drawFramebuffer->getDrawbufferStateCount(); ++drawbufferIdx)
+ {
+ const FramebufferAttachment *attachment =
+ drawFramebuffer->getDrawBuffer(drawbufferIdx);
+ if (attachment)
+ {
+ if (!(attachment->type() == GL_TEXTURE &&
+ attachment->getTextureImageIndex().type == GL_TEXTURE_2D) &&
+ attachment->type() != GL_RENDERBUFFER &&
+ attachment->type() != GL_FRAMEBUFFER_DEFAULT)
+ {
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
+ }
+
+ // Return an error if the destination formats do not match
+ if (attachment->getInternalFormat() != readColorAttachment->getInternalFormat())
+ {
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
+ }
+ }
+ }
+
+ int readSamples = readFramebuffer->getSamples(context->getData());
+
+ if (readSamples != 0 &&
+ IsPartialBlit(context, readColorAttachment, drawColorAttachment, srcX0, srcY0,
+ srcX1, srcY1, dstX0, dstY0, dstX1, dstY1))
+ {
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
+ }
+ }
+ }
+
+ GLenum masks[] = {GL_DEPTH_BUFFER_BIT, GL_STENCIL_BUFFER_BIT};
+ GLenum attachments[] = {GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT};
+ for (size_t i = 0; i < 2; i++)
+ {
+ if (mask & masks[i])
+ {
+ const FramebufferAttachment *readBuffer =
+ readFramebuffer->getAttachment(attachments[i]);
+ const FramebufferAttachment *drawBuffer =
+ drawFramebuffer->getAttachment(attachments[i]);
+
+ if (readBuffer && drawBuffer)
+ {
+ if (IsPartialBlit(context, readBuffer, drawBuffer, srcX0, srcY0, srcX1, srcY1,
+ dstX0, dstY0, dstX1, dstY1))
+ {
+ // only whole-buffer copies are permitted
+ ERR(
+ "Only whole-buffer depth and stencil blits are supported by this "
+ "implementation.");
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
+ }
+
+ if (readBuffer->getSamples() != 0 || drawBuffer->getSamples() != 0)
+ {
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
+ }
+ }
+ }
+ }
+
+ return ValidateBlitFramebufferParameters(context, srcX0, srcY0, srcX1, srcY1, dstX0, dstY0,
+ dstX1, dstY1, mask, filter);
+}
+
+bool ValidateClear(ValidationContext *context, GLbitfield mask)
+{
+ const Framebuffer *framebufferObject = context->getState().getDrawFramebuffer();
+ ASSERT(framebufferObject);
+
+ if (framebufferObject->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
+ {
+ context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
+ return false;
+ }
+
+ if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) != 0)
+ {
+ context->recordError(Error(GL_INVALID_VALUE));
+ return false;
+ }
+
+ return true;
+}
+
+bool ValidateDrawBuffersEXT(ValidationContext *context, GLsizei n, const GLenum *bufs)
+{
+ if (!context->getExtensions().drawBuffers)
+ {
+ context->recordError(Error(GL_INVALID_OPERATION, "Extension not supported."));
+ return false;
+ }
+
+ return ValidateDrawBuffersBase(context, n, bufs);
}
+
+} // namespace gl
diff --git a/src/3rdparty/angle/src/libANGLE/validationES2.h b/src/3rdparty/angle/src/libANGLE/validationES2.h
index b9c1fd3bc4..1b2cf13f60 100644
--- a/src/3rdparty/angle/src/libANGLE/validationES2.h
+++ b/src/3rdparty/angle/src/libANGLE/validationES2.h
@@ -10,18 +10,28 @@
#define LIBANGLE_VALIDATION_ES2_H_
#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
namespace gl
{
-
class Context;
+class ValidationContext;
bool ValidateES2TexImageParameters(Context *context, GLenum target, GLint level, GLenum internalformat, bool isCompressed, bool isSubImage,
GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
GLint border, GLenum format, GLenum type, const GLvoid *pixels);
-bool ValidateES2CopyTexImageParameters(Context* context, GLenum target, GLint level, GLenum internalformat, bool isSubImage,
- GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height,
+bool ValidateES2CopyTexImageParameters(ValidationContext *context,
+ GLenum target,
+ GLint level,
+ GLenum internalformat,
+ bool isSubImage,
+ GLint xoffset,
+ GLint yoffset,
+ GLint x,
+ GLint y,
+ GLsizei width,
+ GLsizei height,
GLint border);
bool ValidateES2TexStorageParameters(Context *context, GLenum target, GLsizei levels, GLenum internalformat,
@@ -29,6 +39,96 @@ bool ValidateES2TexStorageParameters(Context *context, GLenum target, GLsizei le
bool ValidES2ReadFormatType(Context *context, GLenum format, GLenum type);
-}
+bool ValidateDiscardFramebufferEXT(Context *context, GLenum target, GLsizei numAttachments,
+ const GLenum *attachments);
+
+bool ValidateDrawBuffersEXT(ValidationContext *context, GLsizei n, const GLenum *bufs);
+
+bool ValidateBindVertexArrayOES(Context *context, GLuint array);
+bool ValidateDeleteVertexArraysOES(Context *context, GLsizei n);
+bool ValidateGenVertexArraysOES(Context *context, GLsizei n);
+bool ValidateIsVertexArrayOES(Context *context);
+
+bool ValidateProgramBinaryOES(Context *context,
+ GLuint program,
+ GLenum binaryFormat,
+ const void *binary,
+ GLint length);
+bool ValidateGetProgramBinaryOES(Context *context,
+ GLuint program,
+ GLsizei bufSize,
+ GLsizei *length,
+ GLenum *binaryFormat,
+ void *binary);
+
+// GL_KHR_debug
+bool ValidateDebugMessageControlKHR(Context *context,
+ GLenum source,
+ GLenum type,
+ GLenum severity,
+ GLsizei count,
+ const GLuint *ids,
+ GLboolean enabled);
+bool ValidateDebugMessageInsertKHR(Context *context,
+ GLenum source,
+ GLenum type,
+ GLuint id,
+ GLenum severity,
+ GLsizei length,
+ const GLchar *buf);
+bool ValidateDebugMessageCallbackKHR(Context *context,
+ GLDEBUGPROCKHR callback,
+ const void *userParam);
+bool ValidateGetDebugMessageLogKHR(Context *context,
+ GLuint count,
+ GLsizei bufSize,
+ GLenum *sources,
+ GLenum *types,
+ GLuint *ids,
+ GLenum *severities,
+ GLsizei *lengths,
+ GLchar *messageLog);
+bool ValidatePushDebugGroupKHR(Context *context,
+ GLenum source,
+ GLuint id,
+ GLsizei length,
+ const GLchar *message);
+bool ValidatePopDebugGroupKHR(Context *context);
+bool ValidateObjectLabelKHR(Context *context,
+ GLenum identifier,
+ GLuint name,
+ GLsizei length,
+ const GLchar *label);
+bool ValidateGetObjectLabelKHR(Context *context,
+ GLenum identifier,
+ GLuint name,
+ GLsizei bufSize,
+ GLsizei *length,
+ GLchar *label);
+bool ValidateObjectPtrLabelKHR(Context *context,
+ const void *ptr,
+ GLsizei length,
+ const GLchar *label);
+bool ValidateGetObjectPtrLabelKHR(Context *context,
+ const void *ptr,
+ GLsizei bufSize,
+ GLsizei *length,
+ GLchar *label);
+bool ValidateGetPointervKHR(Context *context, GLenum pname, void **params);
+bool ValidateBlitFramebufferANGLE(Context *context,
+ GLint srcX0,
+ GLint srcY0,
+ GLint srcX1,
+ GLint srcY1,
+ GLint dstX0,
+ GLint dstY0,
+ GLint dstX1,
+ GLint dstY1,
+ GLbitfield mask,
+ GLenum filter);
+
+bool ValidateClear(ValidationContext *context, GLbitfield mask);
+
+} // namespace gl
#endif // LIBANGLE_VALIDATION_ES2_H_
diff --git a/src/3rdparty/angle/src/libANGLE/validationES3.cpp b/src/3rdparty/angle/src/libANGLE/validationES3.cpp
index e141bb6ece..e08e5d261b 100644
--- a/src/3rdparty/angle/src/libANGLE/validationES3.cpp
+++ b/src/3rdparty/angle/src/libANGLE/validationES3.cpp
@@ -131,6 +131,15 @@ ES3FormatCombinationSet BuildES3FormatSet()
InsertES3FormatCombo(&set, GL_ALPHA, GL_ALPHA, GL_UNSIGNED_BYTE );
InsertES3FormatCombo(&set, GL_SRGB_ALPHA_EXT, GL_SRGB_ALPHA_EXT, GL_UNSIGNED_BYTE );
InsertES3FormatCombo(&set, GL_SRGB_EXT, GL_SRGB_EXT, GL_UNSIGNED_BYTE );
+ InsertES3FormatCombo(&set, GL_RG, GL_RG, GL_UNSIGNED_BYTE );
+ InsertES3FormatCombo(&set, GL_RG, GL_RG, GL_FLOAT );
+ InsertES3FormatCombo(&set, GL_RG, GL_RG, GL_HALF_FLOAT );
+ InsertES3FormatCombo(&set, GL_RG, GL_RG, GL_HALF_FLOAT_OES );
+ InsertES3FormatCombo(&set, GL_RED, GL_RED, GL_UNSIGNED_BYTE );
+ InsertES3FormatCombo(&set, GL_RED, GL_RED, GL_FLOAT );
+ InsertES3FormatCombo(&set, GL_RED, GL_RED, GL_HALF_FLOAT );
+ InsertES3FormatCombo(&set, GL_RED, GL_RED, GL_HALF_FLOAT_OES );
+ InsertES3FormatCombo(&set, GL_DEPTH_STENCIL, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8 );
// Depth stencil formats
InsertES3FormatCombo(&set, GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT );
@@ -145,6 +154,8 @@ ES3FormatCombinationSet BuildES3FormatSet()
InsertES3FormatCombo(&set, GL_SRGB8, GL_SRGB_EXT, GL_UNSIGNED_BYTE );
// From GL_OES_texture_float
+ InsertES3FormatCombo(&set, GL_RGBA, GL_RGBA, GL_FLOAT );
+ InsertES3FormatCombo(&set, GL_RGB, GL_RGB, GL_FLOAT );
InsertES3FormatCombo(&set, GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_FLOAT );
InsertES3FormatCombo(&set, GL_LUMINANCE, GL_LUMINANCE, GL_FLOAT );
InsertES3FormatCombo(&set, GL_ALPHA, GL_ALPHA, GL_FLOAT );
@@ -186,44 +197,19 @@ ES3FormatCombinationSet BuildES3FormatSet()
// From GL_ANGLE_depth_texture
InsertES3FormatCombo(&set, GL_DEPTH_COMPONENT32_OES, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT_24_8_OES );
- // Compressed formats
- // From ES 3.0.1 spec, table 3.16
- // | Internal format | Format | Type |
- // | | | |
- InsertES3FormatCombo(&set, GL_COMPRESSED_R11_EAC, GL_COMPRESSED_R11_EAC, GL_UNSIGNED_BYTE);
- InsertES3FormatCombo(&set, GL_COMPRESSED_R11_EAC, GL_COMPRESSED_R11_EAC, GL_UNSIGNED_BYTE);
- InsertES3FormatCombo(&set, GL_COMPRESSED_SIGNED_R11_EAC, GL_COMPRESSED_SIGNED_R11_EAC, GL_UNSIGNED_BYTE);
- InsertES3FormatCombo(&set, GL_COMPRESSED_RG11_EAC, GL_COMPRESSED_RG11_EAC, GL_UNSIGNED_BYTE);
- InsertES3FormatCombo(&set, GL_COMPRESSED_SIGNED_RG11_EAC, GL_COMPRESSED_SIGNED_RG11_EAC, GL_UNSIGNED_BYTE);
- InsertES3FormatCombo(&set, GL_COMPRESSED_RGB8_ETC2, GL_COMPRESSED_RGB8_ETC2, GL_UNSIGNED_BYTE);
- InsertES3FormatCombo(&set, GL_COMPRESSED_SRGB8_ETC2, GL_COMPRESSED_SRGB8_ETC2, GL_UNSIGNED_BYTE);
- InsertES3FormatCombo(&set, GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL_UNSIGNED_BYTE);
- InsertES3FormatCombo(&set, GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL_UNSIGNED_BYTE);
- InsertES3FormatCombo(&set, GL_COMPRESSED_RGBA8_ETC2_EAC, GL_COMPRESSED_RGBA8_ETC2_EAC, GL_UNSIGNED_BYTE);
- InsertES3FormatCombo(&set, GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC, GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC, GL_UNSIGNED_BYTE);
-
-
- // From GL_EXT_texture_compression_dxt1
- InsertES3FormatCombo(&set, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_UNSIGNED_BYTE);
- InsertES3FormatCombo(&set, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, GL_UNSIGNED_BYTE);
-
- // From GL_ANGLE_texture_compression_dxt3
- InsertES3FormatCombo(&set, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, GL_UNSIGNED_BYTE);
-
- // From GL_ANGLE_texture_compression_dxt5
- InsertES3FormatCombo(&set, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, GL_UNSIGNED_BYTE);
-
return set;
}
static bool ValidateTexImageFormatCombination(gl::Context *context, GLenum internalFormat, GLenum format, GLenum type)
{
- // Note: dEQP 2013.4 expects an INVALID_VALUE error for TexImage3D with an invalid
- // internal format. (dEQP-GLES3.functional.negative_api.texture.teximage3d)
+ // For historical reasons, glTexImage2D and glTexImage3D pass in their internal format as a
+ // GLint instead of a GLenum. Therefor an invalid internal format gives a GL_INVALID_VALUE
+ // error instead of a GL_INVALID_ENUM error. As this validation function is only called in
+ // the validation codepaths for glTexImage2D/3D, we record a GL_INVALID_VALUE error.
const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat);
if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions()))
{
- context->recordError(Error(GL_INVALID_ENUM));
+ context->recordError(Error(GL_INVALID_VALUE));
return false;
}
@@ -276,18 +262,25 @@ static bool ValidateTexImageFormatCombination(gl::Context *context, GLenum inter
return true;
}
-bool ValidateES3TexImageParameters(Context *context, GLenum target, GLint level, GLenum internalformat, bool isCompressed, bool isSubImage,
- GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
- GLint border, GLenum format, GLenum type, const GLvoid *pixels)
+bool ValidateES3TexImageParametersBase(Context *context,
+ GLenum target,
+ GLint level,
+ GLenum internalformat,
+ bool isCompressed,
+ bool isSubImage,
+ GLint xoffset,
+ GLint yoffset,
+ GLint zoffset,
+ GLsizei width,
+ GLsizei height,
+ GLsizei depth,
+ GLint border,
+ GLenum format,
+ GLenum type,
+ const GLvoid *pixels)
{
- if (!ValidTexture2DDestinationTarget(context, target))
- {
- context->recordError(Error(GL_INVALID_ENUM));
- return false;
- }
-
// Validate image size
- if (!ValidImageSize(context, target, level, width, height, depth))
+ if (!ValidImageSizeParameters(context, target, level, width, height, depth, isSubImage))
{
context->recordError(Error(GL_INVALID_VALUE));
return false;
@@ -354,7 +347,7 @@ bool ValidateES3TexImageParameters(Context *context, GLenum target, GLint level,
case GL_TEXTURE_2D_ARRAY:
if (static_cast<GLuint>(width) > (caps.max2DTextureSize >> level) ||
static_cast<GLuint>(height) > (caps.max2DTextureSize >> level) ||
- static_cast<GLuint>(depth) > (caps.maxArrayTextureLayers >> level))
+ static_cast<GLuint>(depth) > caps.maxArrayTextureLayers)
{
context->recordError(Error(GL_INVALID_VALUE));
return false;
@@ -373,7 +366,7 @@ bool ValidateES3TexImageParameters(Context *context, GLenum target, GLint level,
return false;
}
- if (texture->isImmutable() && !isSubImage)
+ if (texture->getImmutableFormat() && !isSubImage)
{
context->recordError(Error(GL_INVALID_OPERATION));
return false;
@@ -384,13 +377,20 @@ bool ValidateES3TexImageParameters(Context *context, GLenum target, GLint level,
const gl::InternalFormat &actualFormatInfo = gl::GetInternalFormatInfo(actualInternalFormat);
if (isCompressed)
{
+ if (!actualFormatInfo.compressed)
+ {
+ context->recordError(Error(
+ GL_INVALID_ENUM, "internalformat is not a supported compressed internal format."));
+ return false;
+ }
+
if (!ValidCompressedImageSize(context, actualInternalFormat, width, height))
{
context->recordError(Error(GL_INVALID_OPERATION));
return false;
}
- if (!actualFormatInfo.compressed)
+ if (!actualFormatInfo.textureSupport(context->getClientVersion(), context->getExtensions()))
{
context->recordError(Error(GL_INVALID_ENUM));
return false;
@@ -511,6 +511,62 @@ bool ValidateES3TexImageParameters(Context *context, GLenum target, GLint level,
return true;
}
+bool ValidateES3TexImage2DParameters(Context *context,
+ GLenum target,
+ GLint level,
+ GLenum internalformat,
+ bool isCompressed,
+ bool isSubImage,
+ GLint xoffset,
+ GLint yoffset,
+ GLint zoffset,
+ GLsizei width,
+ GLsizei height,
+ GLsizei depth,
+ GLint border,
+ GLenum format,
+ GLenum type,
+ const GLvoid *pixels)
+{
+ if (!ValidTexture2DDestinationTarget(context, target))
+ {
+ context->recordError(Error(GL_INVALID_ENUM));
+ return false;
+ }
+
+ return ValidateES3TexImageParametersBase(context, target, level, internalformat, isCompressed,
+ isSubImage, xoffset, yoffset, zoffset, width, height,
+ depth, border, format, type, pixels);
+}
+
+bool ValidateES3TexImage3DParameters(Context *context,
+ GLenum target,
+ GLint level,
+ GLenum internalformat,
+ bool isCompressed,
+ bool isSubImage,
+ GLint xoffset,
+ GLint yoffset,
+ GLint zoffset,
+ GLsizei width,
+ GLsizei height,
+ GLsizei depth,
+ GLint border,
+ GLenum format,
+ GLenum type,
+ const GLvoid *pixels)
+{
+ if (!ValidTexture3DDestinationTarget(context, target))
+ {
+ context->recordError(Error(GL_INVALID_ENUM));
+ return false;
+ }
+
+ return ValidateES3TexImageParametersBase(context, target, level, internalformat, isCompressed,
+ isSubImage, xoffset, yoffset, zoffset, width, height,
+ depth, border, format, type, pixels);
+}
+
struct EffectiveInternalFormatInfo
{
GLenum mEffectiveFormat;
@@ -795,9 +851,19 @@ static bool IsValidES3CopyTexImageCombination(GLenum textureInternalFormat, GLen
return false;
}
-bool ValidateES3CopyTexImageParameters(Context *context, GLenum target, GLint level, GLenum internalformat,
- bool isSubImage, GLint xoffset, GLint yoffset, GLint zoffset,
- GLint x, GLint y, GLsizei width, GLsizei height, GLint border)
+bool ValidateES3CopyTexImageParametersBase(ValidationContext *context,
+ GLenum target,
+ GLint level,
+ GLenum internalformat,
+ bool isSubImage,
+ GLint xoffset,
+ GLint yoffset,
+ GLint zoffset,
+ GLint x,
+ GLint y,
+ GLsizei width,
+ GLsizei height,
+ GLint border)
{
GLenum textureInternalFormat;
if (!ValidateCopyTexImageParametersBase(context, target, level, internalformat, isSubImage,
@@ -807,7 +873,9 @@ bool ValidateES3CopyTexImageParameters(Context *context, GLenum target, GLint le
return false;
}
- gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
+ const auto &state = context->getState();
+ const gl::Framebuffer *framebuffer = state.getReadFramebuffer();
+ GLuint readFramebufferID = framebuffer->id();
if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
{
@@ -815,20 +883,19 @@ bool ValidateES3CopyTexImageParameters(Context *context, GLenum target, GLint le
return false;
}
- if (context->getState().getReadFramebuffer()->id() != 0 &&
- framebuffer->getSamples(context->getData()) != 0)
+ if (readFramebufferID != 0 && framebuffer->getSamples(context->getData()) != 0)
{
context->recordError(Error(GL_INVALID_OPERATION));
return false;
}
- gl::FramebufferAttachment *source = framebuffer->getReadColorbuffer();
+ const gl::FramebufferAttachment *source = framebuffer->getReadColorbuffer();
GLenum colorbufferInternalFormat = source->getInternalFormat();
if (isSubImage)
{
if (!IsValidES3CopyTexImageCombination(textureInternalFormat, colorbufferInternalFormat,
- context->getState().getReadFramebuffer()->id()))
+ readFramebufferID))
{
context->recordError(Error(GL_INVALID_OPERATION));
return false;
@@ -837,7 +904,7 @@ bool ValidateES3CopyTexImageParameters(Context *context, GLenum target, GLint le
else
{
if (!gl::IsValidES3CopyTexImageCombination(internalformat, colorbufferInternalFormat,
- context->getState().getReadFramebuffer()->id()))
+ readFramebufferID))
{
context->recordError(Error(GL_INVALID_OPERATION));
return false;
@@ -848,8 +915,63 @@ bool ValidateES3CopyTexImageParameters(Context *context, GLenum target, GLint le
return (width > 0 && height > 0);
}
-bool ValidateES3TexStorageParameters(Context *context, GLenum target, GLsizei levels, GLenum internalformat,
- GLsizei width, GLsizei height, GLsizei depth)
+bool ValidateES3CopyTexImage2DParameters(ValidationContext *context,
+ GLenum target,
+ GLint level,
+ GLenum internalformat,
+ bool isSubImage,
+ GLint xoffset,
+ GLint yoffset,
+ GLint zoffset,
+ GLint x,
+ GLint y,
+ GLsizei width,
+ GLsizei height,
+ GLint border)
+{
+ if (!ValidTexture2DDestinationTarget(context, target))
+ {
+ context->recordError(Error(GL_INVALID_ENUM));
+ return false;
+ }
+
+ return ValidateES3CopyTexImageParametersBase(context, target, level, internalformat, isSubImage,
+ xoffset, yoffset, zoffset, x, y, width, height,
+ border);
+}
+
+bool ValidateES3CopyTexImage3DParameters(ValidationContext *context,
+ GLenum target,
+ GLint level,
+ GLenum internalformat,
+ bool isSubImage,
+ GLint xoffset,
+ GLint yoffset,
+ GLint zoffset,
+ GLint x,
+ GLint y,
+ GLsizei width,
+ GLsizei height,
+ GLint border)
+{
+ if (!ValidTexture3DDestinationTarget(context, target))
+ {
+ context->recordError(Error(GL_INVALID_ENUM));
+ return false;
+ }
+
+ return ValidateES3CopyTexImageParametersBase(context, target, level, internalformat, isSubImage,
+ xoffset, yoffset, zoffset, x, y, width, height,
+ border);
+}
+
+bool ValidateES3TexStorageParametersBase(Context *context,
+ GLenum target,
+ GLsizei levels,
+ GLenum internalformat,
+ GLsizei width,
+ GLsizei height,
+ GLsizei depth)
{
if (width < 1 || height < 1 || depth < 1 || levels < 1)
{
@@ -857,7 +979,13 @@ bool ValidateES3TexStorageParameters(Context *context, GLenum target, GLsizei le
return false;
}
- if (levels > gl::log2(std::max(std::max(width, height), depth)) + 1)
+ GLsizei maxDim = std::max(width, height);
+ if (target != GL_TEXTURE_2D_ARRAY)
+ {
+ maxDim = std::max(maxDim, depth);
+ }
+
+ if (levels > gl::log2(maxDim) + 1)
{
context->recordError(Error(GL_INVALID_OPERATION));
return false;
@@ -919,7 +1047,7 @@ bool ValidateES3TexStorageParameters(Context *context, GLenum target, GLsizei le
break;
default:
- context->recordError(Error(GL_INVALID_ENUM));
+ UNREACHABLE();
return false;
}
@@ -930,7 +1058,7 @@ bool ValidateES3TexStorageParameters(Context *context, GLenum target, GLsizei le
return false;
}
- if (texture->isImmutable())
+ if (texture->getImmutableFormat())
{
context->recordError(Error(GL_INVALID_OPERATION));
return false;
@@ -952,6 +1080,108 @@ bool ValidateES3TexStorageParameters(Context *context, GLenum target, GLsizei le
return true;
}
+bool ValidateES3TexStorage2DParameters(Context *context,
+ GLenum target,
+ GLsizei levels,
+ GLenum internalformat,
+ GLsizei width,
+ GLsizei height,
+ GLsizei depth)
+{
+ if (!ValidTexture2DTarget(context, target))
+ {
+ context->recordError(Error(GL_INVALID_ENUM));
+ return false;
+ }
+
+ return ValidateES3TexStorageParametersBase(context, target, levels, internalformat, width,
+ height, depth);
+}
+
+bool ValidateES3TexStorage3DParameters(Context *context,
+ GLenum target,
+ GLsizei levels,
+ GLenum internalformat,
+ GLsizei width,
+ GLsizei height,
+ GLsizei depth)
+{
+ if (!ValidTexture3DTarget(context, target))
+ {
+ context->recordError(Error(GL_INVALID_ENUM));
+ return false;
+ }
+
+ return ValidateES3TexStorageParametersBase(context, target, levels, internalformat, width,
+ height, depth);
+}
+
+bool ValidateGenQueries(gl::Context *context, GLsizei n, const GLuint *ids)
+{
+ if (context->getClientVersion() < 3)
+ {
+ context->recordError(Error(GL_INVALID_OPERATION, "GLES version < 3.0"));
+ return false;
+ }
+
+ return ValidateGenQueriesBase(context, n, ids);
+}
+
+bool ValidateDeleteQueries(gl::Context *context, GLsizei n, const GLuint *ids)
+{
+ if (context->getClientVersion() < 3)
+ {
+ context->recordError(Error(GL_INVALID_OPERATION, "GLES version < 3.0"));
+ return false;
+ }
+
+ return ValidateDeleteQueriesBase(context, n, ids);
+}
+
+bool ValidateBeginQuery(gl::Context *context, GLenum target, GLuint id)
+{
+ if (context->getClientVersion() < 3)
+ {
+ context->recordError(Error(GL_INVALID_OPERATION, "GLES version < 3.0"));
+ return false;
+ }
+
+ return ValidateBeginQueryBase(context, target, id);
+}
+
+bool ValidateEndQuery(gl::Context *context, GLenum target)
+{
+ if (context->getClientVersion() < 3)
+ {
+ context->recordError(Error(GL_INVALID_OPERATION, "GLES version < 3.0"));
+ return false;
+ }
+
+ return ValidateEndQueryBase(context, target);
+}
+
+bool ValidateGetQueryiv(Context *context, GLenum target, GLenum pname, GLint *params)
+{
+ if (context->getClientVersion() < 3)
+ {
+ context->recordError(Error(GL_INVALID_OPERATION, "GLES version < 3.0"));
+ return false;
+ }
+
+ return ValidateGetQueryivBase(context, target, pname);
+}
+
+bool ValidateGetQueryObjectuiv(Context *context, GLuint id, GLenum pname, GLuint *params)
+{
+ if (context->getClientVersion() < 3)
+ {
+ context->recordError(Error(GL_INVALID_OPERATION, "GLES version < 3.0"));
+ return false;
+ }
+
+ return ValidateGetQueryObjectValueBase(context, id, pname);
+}
+
bool ValidateFramebufferTextureLayer(Context *context, GLenum target, GLenum attachment,
GLuint texture, GLint level, GLint layer)
{
@@ -1132,9 +1362,15 @@ bool ValidateES3RenderbufferStorageParameters(gl::Context *context, GLenum targe
return true;
}
-bool ValidateInvalidateFramebufferParameters(Context *context, GLenum target, GLsizei numAttachments,
- const GLenum* attachments)
+bool ValidateInvalidateFramebuffer(Context *context, GLenum target, GLsizei numAttachments,
+ const GLenum *attachments)
{
+ if (context->getClientVersion() < 3)
+ {
+ context->recordError(Error(GL_INVALID_OPERATION, "Operation only supported on ES 3.0 and above"));
+ return false;
+ }
+
bool defaultFramebuffer = false;
switch (target)
@@ -1147,59 +1383,14 @@ bool ValidateInvalidateFramebufferParameters(Context *context, GLenum target, GL
defaultFramebuffer = context->getState().getReadFramebuffer()->id() == 0;
break;
default:
- context->recordError(Error(GL_INVALID_ENUM));
- return false;
- }
-
- for (int i = 0; i < numAttachments; ++i)
- {
- if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT15)
- {
- if (defaultFramebuffer)
- {
- context->recordError(Error(GL_INVALID_ENUM));
- return false;
- }
-
- if (attachments[i] >= GL_COLOR_ATTACHMENT0 + context->getCaps().maxColorAttachments)
- {
- context->recordError(Error(GL_INVALID_OPERATION));
- return false;
- }
- }
- else
- {
- switch (attachments[i])
- {
- case GL_DEPTH_ATTACHMENT:
- case GL_STENCIL_ATTACHMENT:
- case GL_DEPTH_STENCIL_ATTACHMENT:
- if (defaultFramebuffer)
- {
- context->recordError(Error(GL_INVALID_ENUM));
- return false;
- }
- break;
- case GL_COLOR:
- case GL_DEPTH:
- case GL_STENCIL:
- if (!defaultFramebuffer)
- {
- context->recordError(Error(GL_INVALID_ENUM));
- return false;
- }
- break;
- default:
- context->recordError(Error(GL_INVALID_ENUM));
- return false;
- }
- }
+ context->recordError(Error(GL_INVALID_ENUM, "Invalid framebuffer target"));
+ return false;
}
- return true;
+ return ValidateDiscardFramebufferBase(context, target, numAttachments, attachments, defaultFramebuffer);
}
-bool ValidateClearBuffer(Context *context)
+bool ValidateClearBuffer(ValidationContext *context)
{
if (context->getClientVersion() < 3)
{
@@ -1279,4 +1470,315 @@ bool ValidateReadBuffer(Context *context, GLenum src)
return true;
}
+bool ValidateCompressedTexImage3D(Context *context,
+ GLenum target,
+ GLint level,
+ GLenum internalformat,
+ GLsizei width,
+ GLsizei height,
+ GLsizei depth,
+ GLint border,
+ GLsizei imageSize,
+ const GLvoid *data)
+{
+ if (context->getClientVersion() < 3)
+ {
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
+ }
+
+ const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
+ if (imageSize < 0 ||
+ static_cast<GLuint>(imageSize) !=
+ formatInfo.computeBlockSize(GL_UNSIGNED_BYTE, width, height))
+ {
+ context->recordError(Error(GL_INVALID_VALUE));
+ return false;
+ }
+
+ // 3D texture target validation
+ if (target != GL_TEXTURE_3D && target != GL_TEXTURE_2D_ARRAY)
+ {
+ context->recordError(
+ Error(GL_INVALID_ENUM, "Must specify a valid 3D texture destination target"));
+ return false;
+ }
+
+ // validateES3TexImageFormat sets the error code if there is an error
+ if (!ValidateES3TexImage3DParameters(context, target, level, internalformat, true, false, 0, 0,
+ 0, width, height, depth, border, GL_NONE, GL_NONE, data))
+ {
+ return false;
+ }
+
+ return true;
}
+
+bool ValidateBindVertexArray(Context *context, GLuint array)
+{
+ if (context->getClientVersion() < 3)
+ {
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
+ }
+
+ return ValidateBindVertexArrayBase(context, array);
+}
+
+bool ValidateDeleteVertexArrays(Context *context, GLsizei n)
+{
+ if (context->getClientVersion() < 3)
+ {
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
+ }
+
+ return ValidateDeleteVertexArraysBase(context, n);
+}
+
+bool ValidateGenVertexArrays(Context *context, GLsizei n)
+{
+ if (context->getClientVersion() < 3)
+ {
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
+ }
+
+ return ValidateGenVertexArraysBase(context, n);
+}
+
+bool ValidateIsVertexArray(Context *context)
+{
+ if (context->getClientVersion() < 3)
+ {
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
+ }
+
+ return true;
+}
+
+bool ValidateProgramBinary(Context *context,
+ GLuint program,
+ GLenum binaryFormat,
+ const void *binary,
+ GLint length)
+{
+ if (context->getClientVersion() < 3)
+ {
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
+ }
+
+ return ValidateProgramBinaryBase(context, program, binaryFormat, binary, length);
+}
+
+bool ValidateGetProgramBinary(Context *context,
+ GLuint program,
+ GLsizei bufSize,
+ GLsizei *length,
+ GLenum *binaryFormat,
+ void *binary)
+{
+ if (context->getClientVersion() < 3)
+ {
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
+ }
+
+ return ValidateGetProgramBinaryBase(context, program, bufSize, length, binaryFormat, binary);
+}
+
+bool ValidateProgramParameter(Context *context, GLuint program, GLenum pname, GLint value)
+{
+ if (context->getClientVersion() < 3)
+ {
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
+ }
+
+ if (GetValidProgram(context, program) == nullptr)
+ {
+ return false;
+ }
+
+ switch (pname)
+ {
+ case GL_PROGRAM_BINARY_RETRIEVABLE_HINT:
+ break;
+
+ default:
+ context->recordError(Error(GL_INVALID_ENUM, "Invalid pname: 0x%X", pname));
+ return false;
+ }
+
+ return true;
+}
+
+bool ValidateBlitFramebuffer(Context *context,
+ GLint srcX0,
+ GLint srcY0,
+ GLint srcX1,
+ GLint srcY1,
+ GLint dstX0,
+ GLint dstY0,
+ GLint dstX1,
+ GLint dstY1,
+ GLbitfield mask,
+ GLenum filter)
+{
+ if (context->getClientVersion() < 3)
+ {
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
+ }
+
+ return ValidateBlitFramebufferParameters(context, srcX0, srcY0, srcX1, srcY1, dstX0, dstY0,
+ dstX1, dstY1, mask, filter);
+}
+
+bool ValidateClearBufferiv(ValidationContext *context,
+ GLenum buffer,
+ GLint drawbuffer,
+ const GLint *value)
+{
+ switch (buffer)
+ {
+ case GL_COLOR:
+ if (drawbuffer < 0 ||
+ static_cast<GLuint>(drawbuffer) >= context->getCaps().maxDrawBuffers)
+ {
+ context->recordError(Error(GL_INVALID_VALUE));
+ return false;
+ }
+ break;
+
+ case GL_STENCIL:
+ if (drawbuffer != 0)
+ {
+ context->recordError(Error(GL_INVALID_VALUE));
+ return false;
+ }
+ break;
+
+ default:
+ context->recordError(Error(GL_INVALID_ENUM));
+ return false;
+ }
+
+ return ValidateClearBuffer(context);
+}
+
+bool ValidateClearBufferuiv(ValidationContext *context,
+ GLenum buffer,
+ GLint drawbuffer,
+ const GLuint *value)
+{
+ switch (buffer)
+ {
+ case GL_COLOR:
+ if (drawbuffer < 0 ||
+ static_cast<GLuint>(drawbuffer) >= context->getCaps().maxDrawBuffers)
+ {
+ context->recordError(Error(GL_INVALID_VALUE));
+ return false;
+ }
+ break;
+
+ default:
+ context->recordError(Error(GL_INVALID_ENUM));
+ return false;
+ }
+
+ return ValidateClearBuffer(context);
+}
+
+bool ValidateClearBufferfv(ValidationContext *context,
+ GLenum buffer,
+ GLint drawbuffer,
+ const GLfloat *value)
+{
+ switch (buffer)
+ {
+ case GL_COLOR:
+ if (drawbuffer < 0 ||
+ static_cast<GLuint>(drawbuffer) >= context->getCaps().maxDrawBuffers)
+ {
+ context->recordError(Error(GL_INVALID_VALUE));
+ return false;
+ }
+ break;
+
+ case GL_DEPTH:
+ if (drawbuffer != 0)
+ {
+ context->recordError(Error(GL_INVALID_VALUE));
+ return false;
+ }
+ break;
+
+ default:
+ context->recordError(Error(GL_INVALID_ENUM));
+ return false;
+ }
+
+ return ValidateClearBuffer(context);
+}
+
+bool ValidateClearBufferfi(ValidationContext *context,
+ GLenum buffer,
+ GLint drawbuffer,
+ GLfloat depth,
+ GLint stencil)
+{
+ switch (buffer)
+ {
+ case GL_DEPTH_STENCIL:
+ if (drawbuffer != 0)
+ {
+ context->recordError(Error(GL_INVALID_VALUE));
+ return false;
+ }
+ break;
+
+ default:
+ context->recordError(Error(GL_INVALID_ENUM));
+ return false;
+ }
+
+ return ValidateClearBuffer(context);
+}
+
+bool ValidateDrawBuffers(ValidationContext *context, GLsizei n, const GLenum *bufs)
+{
+ if (context->getClientVersion() < 3)
+ {
+ context->recordError(Error(GL_INVALID_OPERATION, "Context does not support GLES3."));
+ return false;
+ }
+
+ return ValidateDrawBuffersBase(context, n, bufs);
+}
+
+bool ValidateCopyTexSubImage3D(Context *context,
+ GLenum target,
+ GLint level,
+ GLint xoffset,
+ GLint yoffset,
+ GLint zoffset,
+ GLint x,
+ GLint y,
+ GLsizei width,
+ GLsizei height)
+{
+ if (context->getClientVersion() < 3)
+ {
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
+ }
+
+ return ValidateES3CopyTexImage3DParameters(context, target, level, GL_NONE, true, xoffset,
+ yoffset, zoffset, x, y, width, height, 0);
+}
+
+} // namespace gl
diff --git a/src/3rdparty/angle/src/libANGLE/validationES3.h b/src/3rdparty/angle/src/libANGLE/validationES3.h
index 517cb5d27f..7bc657790a 100644
--- a/src/3rdparty/angle/src/libANGLE/validationES3.h
+++ b/src/3rdparty/angle/src/libANGLE/validationES3.h
@@ -13,19 +13,145 @@
namespace gl
{
-
class Context;
-
-bool ValidateES3TexImageParameters(Context *context, GLenum target, GLint level, GLenum internalformat, bool isCompressed, bool isSubImage,
- GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
- GLint border, GLenum format, GLenum type, const GLvoid *pixels);
-
-bool ValidateES3CopyTexImageParameters(Context *context, GLenum target, GLint level, GLenum internalformat,
- bool isSubImage, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y,
- GLsizei width, GLsizei height, GLint border);
-
-bool ValidateES3TexStorageParameters(Context *context, GLenum target, GLsizei levels, GLenum internalformat,
- GLsizei width, GLsizei height, GLsizei depth);
+class ValidationContext;
+
+bool ValidateES3TexImageParametersBase(ValidationContext *context,
+ GLenum target,
+ GLint level,
+ GLenum internalformat,
+ bool isCompressed,
+ bool isSubImage,
+ GLint xoffset,
+ GLint yoffset,
+ GLint zoffset,
+ GLsizei width,
+ GLsizei height,
+ GLsizei depth,
+ GLint border,
+ GLenum format,
+ GLenum type,
+ const GLvoid *pixels);
+
+bool ValidateES3TexStorageParameters(Context *context,
+ GLenum target,
+ GLsizei levels,
+ GLenum internalformat,
+ GLsizei width,
+ GLsizei height,
+ GLsizei depth);
+
+bool ValidateES3TexImage2DParameters(Context *context,
+ GLenum target,
+ GLint level,
+ GLenum internalformat,
+ bool isCompressed,
+ bool isSubImage,
+ GLint xoffset,
+ GLint yoffset,
+ GLint zoffset,
+ GLsizei width,
+ GLsizei height,
+ GLsizei depth,
+ GLint border,
+ GLenum format,
+ GLenum type,
+ const GLvoid *pixels);
+
+bool ValidateES3TexImage3DParameters(Context *context,
+ GLenum target,
+ GLint level,
+ GLenum internalformat,
+ bool isCompressed,
+ bool isSubImage,
+ GLint xoffset,
+ GLint yoffset,
+ GLint zoffset,
+ GLsizei width,
+ GLsizei height,
+ GLsizei depth,
+ GLint border,
+ GLenum format,
+ GLenum type,
+ const GLvoid *pixels);
+
+bool ValidateES3CopyTexImageParametersBase(ValidationContext *context,
+ GLenum target,
+ GLint level,
+ GLenum internalformat,
+ bool isSubImage,
+ GLint xoffset,
+ GLint yoffset,
+ GLint zoffset,
+ GLint x,
+ GLint y,
+ GLsizei width,
+ GLsizei height,
+ GLint border);
+
+bool ValidateES3CopyTexImage2DParameters(ValidationContext *context,
+ GLenum target,
+ GLint level,
+ GLenum internalformat,
+ bool isSubImage,
+ GLint xoffset,
+ GLint yoffset,
+ GLint zoffset,
+ GLint x,
+ GLint y,
+ GLsizei width,
+ GLsizei height,
+ GLint border);
+
+bool ValidateES3CopyTexImage3DParameters(ValidationContext *context,
+ GLenum target,
+ GLint level,
+ GLenum internalformat,
+ bool isSubImage,
+ GLint xoffset,
+ GLint yoffset,
+ GLint zoffset,
+ GLint x,
+ GLint y,
+ GLsizei width,
+ GLsizei height,
+ GLint border);
+
+bool ValidateES3TexStorageParametersBase(Context *context,
+ GLenum target,
+ GLsizei levels,
+ GLenum internalformat,
+ GLsizei width,
+ GLsizei height,
+ GLsizei depth);
+
+bool ValidateES3TexStorage2DParameters(Context *context,
+ GLenum target,
+ GLsizei levels,
+ GLenum internalformat,
+ GLsizei width,
+ GLsizei height,
+ GLsizei depth);
+
+bool ValidateES3TexStorage3DParameters(Context *context,
+ GLenum target,
+ GLsizei levels,
+ GLenum internalformat,
+ GLsizei width,
+ GLsizei height,
+ GLsizei depth);
+
+bool ValidateGenQueries(Context *context, GLsizei n, const GLuint *ids);
+
+bool ValidateDeleteQueries(Context *context, GLsizei n, const GLuint *ids);
+
+bool ValidateBeginQuery(Context *context, GLenum target, GLuint id);
+
+bool ValidateEndQuery(Context *context, GLenum target);
+
+bool ValidateGetQueryiv(Context *context, GLenum target, GLenum pname, GLint *params);
+
+bool ValidateGetQueryObjectuiv(Context *context, GLuint id, GLenum pname, GLuint *params);
bool ValidateFramebufferTextureLayer(Context *context, GLenum target, GLenum attachment,
GLuint texture, GLint level, GLint layer);
@@ -35,15 +161,83 @@ bool ValidES3ReadFormatType(Context *context, GLenum internalFormat, GLenum form
bool ValidateES3RenderbufferStorageParameters(Context *context, GLenum target, GLsizei samples,
GLenum internalformat, GLsizei width, GLsizei height);
-bool ValidateInvalidateFramebufferParameters(Context *context, GLenum target, GLsizei numAttachments,
- const GLenum* attachments);
+bool ValidateInvalidateFramebuffer(Context *context, GLenum target, GLsizei numAttachments,
+ const GLenum *attachments);
-bool ValidateClearBuffer(Context *context);
+bool ValidateClearBuffer(ValidationContext *context);
bool ValidateGetUniformuiv(Context *context, GLuint program, GLint location, GLuint* params);
bool ValidateReadBuffer(Context *context, GLenum mode);
-}
+bool ValidateCompressedTexImage3D(Context *context,
+ GLenum target,
+ GLint level,
+ GLenum internalformat,
+ GLsizei width,
+ GLsizei height,
+ GLsizei depth,
+ GLint border,
+ GLsizei imageSize,
+ const GLvoid *data);
+
+bool ValidateBindVertexArray(Context *context, GLuint array);
+bool ValidateDeleteVertexArrays(Context *context, GLsizei n);
+bool ValidateGenVertexArrays(Context *context, GLsizei n);
+bool ValidateIsVertexArray(Context *context);
+
+bool ValidateProgramBinary(Context *context,
+ GLuint program,
+ GLenum binaryFormat,
+ const void *binary,
+ GLint length);
+bool ValidateGetProgramBinary(Context *context,
+ GLuint program,
+ GLsizei bufSize,
+ GLsizei *length,
+ GLenum *binaryFormat,
+ void *binary);
+bool ValidateProgramParameter(Context *context, GLuint program, GLenum pname, GLint value);
+bool ValidateBlitFramebuffer(Context *context,
+ GLint srcX0,
+ GLint srcY0,
+ GLint srcX1,
+ GLint srcY1,
+ GLint dstX0,
+ GLint dstY0,
+ GLint dstX1,
+ GLint dstY1,
+ GLbitfield mask,
+ GLenum filter);
+bool ValidateClearBufferiv(ValidationContext *context,
+ GLenum buffer,
+ GLint drawbuffer,
+ const GLint *value);
+bool ValidateClearBufferuiv(ValidationContext *context,
+ GLenum buffer,
+ GLint drawbuffer,
+ const GLuint *value);
+bool ValidateClearBufferfv(ValidationContext *context,
+ GLenum buffer,
+ GLint drawbuffer,
+ const GLfloat *value);
+bool ValidateClearBufferfi(ValidationContext *context,
+ GLenum buffer,
+ GLint drawbuffer,
+ GLfloat depth,
+ GLint stencil);
+bool ValidateDrawBuffers(ValidationContext *context, GLsizei n, const GLenum *bufs);
+bool ValidateCopyTexSubImage3D(Context *context,
+ GLenum target,
+ GLint level,
+ GLint xoffset,
+ GLint yoffset,
+ GLint zoffset,
+ GLint x,
+ GLint y,
+ GLsizei width,
+ GLsizei height);
+
+} // namespace gl
#endif // LIBANGLE_VALIDATION_ES3_H_
diff --git a/src/3rdparty/angle/src/libEGL/libEGL.cpp b/src/3rdparty/angle/src/libEGL/libEGL.cpp
index d09219e308..f28f40fcf5 100644
--- a/src/3rdparty/angle/src/libEGL/libEGL.cpp
+++ b/src/3rdparty/angle/src/libEGL/libEGL.cpp
@@ -242,6 +242,47 @@ EGLDisplay EGLAPIENTRY eglGetPlatformDisplayEXT(EGLenum platform, void *native_d
return egl::GetPlatformDisplayEXT(platform, native_display, attrib_list);
}
+EGLBoolean EGLAPIENTRY eglQueryDisplayAttribEXT(EGLDisplay dpy, EGLint attribute, EGLAttrib *value)
+{
+ return egl::QueryDisplayAttribEXT(dpy, attribute, value);
+}
+
+EGLBoolean EGLAPIENTRY eglQueryDeviceAttribEXT(EGLDeviceEXT device, EGLint attribute, EGLAttrib *value)
+{
+ return egl::QueryDeviceAttribEXT(device, attribute, value);
+}
+
+const char * EGLAPIENTRY eglQueryDeviceStringEXT(EGLDeviceEXT device, EGLint name)
+{
+ return egl::QueryDeviceStringEXT(device, name);
+}
+
+EGLImageKHR EGLAPIENTRY eglCreateImageKHR(EGLDisplay dpy,
+ EGLContext ctx,
+ EGLenum target,
+ EGLClientBuffer buffer,
+ const EGLint *attrib_list)
+{
+ return egl::CreateImageKHR(dpy, ctx, target, buffer, attrib_list);
+}
+
+EGLBoolean EGLAPIENTRY eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR image)
+{
+ return egl::DestroyImageKHR(dpy, image);
+}
+
+EGLDeviceEXT EGLAPIENTRY eglCreateDeviceANGLE(EGLint device_type,
+ void *native_device,
+ const EGLAttrib *attrib_list)
+{
+ return egl::CreateDeviceANGLE(device_type, native_device, attrib_list);
+}
+
+EGLBoolean EGLAPIENTRY eglReleaseDeviceANGLE(EGLDeviceEXT device)
+{
+ return egl::ReleaseDeviceANGLE(device);
+}
+
__eglMustCastToProperFunctionPointerType EGLAPIENTRY eglGetProcAddress(const char *procname)
{
return egl::GetProcAddress(procname);
diff --git a/src/3rdparty/angle/src/libEGL/libEGL.def b/src/3rdparty/angle/src/libEGL/libEGL.def
index 823cba2f88..74b7c2ae14 100644
--- a/src/3rdparty/angle/src/libEGL/libEGL.def
+++ b/src/3rdparty/angle/src/libEGL/libEGL.def
@@ -39,6 +39,13 @@ EXPORTS
eglGetPlatformDisplayEXT @35
eglQuerySurfacePointerANGLE @36
eglPostSubBufferNV @37
+ eglQueryDisplayAttribEXT @48
+ eglQueryDeviceAttribEXT @49
+ eglQueryDeviceStringEXT @50
+ eglCreateImageKHR @51
+ eglDestroyImageKHR @52
+ eglCreateDeviceANGLE @53
+ eglReleaseDeviceANGLE @54
; 1.5 entry points
eglCreateSync @38
diff --git a/src/3rdparty/angle/src/libEGL/libEGL_mingw32.def b/src/3rdparty/angle/src/libEGL/libEGL_mingw32.def
index 6a771a54b8..d8fcf51620 100644
--- a/src/3rdparty/angle/src/libEGL/libEGL_mingw32.def
+++ b/src/3rdparty/angle/src/libEGL/libEGL_mingw32.def
@@ -39,6 +39,13 @@ EXPORTS
eglGetPlatformDisplayEXT@12 @35
eglQuerySurfacePointerANGLE@16 @36
eglPostSubBufferNV@24 @37
+ eglQueryDisplayAttribEXT@12 @48
+ eglQueryDeviceAttribEXT@12 @49
+ eglQueryDeviceStringEXT@8 @50
+ eglCreateImageKHR@20 @51
+ eglDestroyImageKHR@8 @52
+ eglCreateDeviceANGLE@12 @53
+ eglReleaseDeviceANGLE@4 @54
; 1.5 entry points
eglCreateSync @38
diff --git a/src/3rdparty/angle/src/libEGL/libEGLd.def b/src/3rdparty/angle/src/libEGL/libEGLd.def
index cab7dc9d24..318e04cfa6 100644
--- a/src/3rdparty/angle/src/libEGL/libEGLd.def
+++ b/src/3rdparty/angle/src/libEGL/libEGLd.def
@@ -39,6 +39,13 @@ EXPORTS
eglGetPlatformDisplayEXT @35
eglQuerySurfacePointerANGLE @36
eglPostSubBufferNV @37
+ eglQueryDisplayAttribEXT @48
+ eglQueryDeviceAttribEXT @49
+ eglQueryDeviceStringEXT @50
+ eglCreateImageKHR @51
+ eglDestroyImageKHR @52
+ eglCreateDeviceANGLE @53
+ eglReleaseDeviceANGLE @54
; 1.5 entry points
eglCreateSync @38
diff --git a/src/3rdparty/angle/src/libEGL/libEGLd_mingw32.def b/src/3rdparty/angle/src/libEGL/libEGLd_mingw32.def
index ab0320dc0d..d322cf67de 100644
--- a/src/3rdparty/angle/src/libEGL/libEGLd_mingw32.def
+++ b/src/3rdparty/angle/src/libEGL/libEGLd_mingw32.def
@@ -39,3 +39,10 @@ EXPORTS
eglGetPlatformDisplayEXT@12 @35
eglQuerySurfacePointerANGLE@16 @36
eglPostSubBufferNV@24 @37
+ eglQueryDisplayAttribEXT@12 @48
+ eglQueryDeviceAttribEXT@12 @49
+ eglQueryDeviceStringEXT@8 @50
+ eglCreateImageKHR@20 @51
+ eglDestroyImageKHR@8 @52
+ eglCreateDeviceANGLE@12 @53
+ eglReleaseDeviceANGLE@4 @54
diff --git a/src/3rdparty/angle/src/libGLESv2/entry_points_egl.cpp b/src/3rdparty/angle/src/libGLESv2/entry_points_egl.cpp
index a6db1585e7..6f9770c57c 100644
--- a/src/3rdparty/angle/src/libGLESv2/entry_points_egl.cpp
+++ b/src/3rdparty/angle/src/libGLESv2/entry_points_egl.cpp
@@ -8,8 +8,9 @@
#include "libGLESv2/entry_points_egl.h"
#include "libGLESv2/entry_points_egl_ext.h"
+#include "libGLESv2/entry_points_gles_2_0.h"
#include "libGLESv2/entry_points_gles_2_0_ext.h"
-#include "libGLESv2/entry_points_gles_3_0_ext.h"
+#include "libGLESv2/entry_points_gles_3_0.h"
#include "libGLESv2/global_state.h"
#include "libANGLE/Context.h"
@@ -40,7 +41,7 @@ EGLDisplay EGLAPIENTRY GetDisplay(EGLNativeDisplayType display_id)
{
EVENT("(EGLNativeDisplayType display_id = 0x%0.8p)", display_id);
- return Display::getDisplay(display_id, AttributeMap());
+ return Display::GetDisplayFromAttribs(reinterpret_cast<void *>(display_id), AttributeMap());
}
EGLBoolean EGLAPIENTRY Initialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
@@ -48,14 +49,13 @@ EGLBoolean EGLAPIENTRY Initialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
EVENT("(EGLDisplay dpy = 0x%0.8p, EGLint *major = 0x%0.8p, EGLint *minor = 0x%0.8p)",
dpy, major, minor);
- if (dpy == EGL_NO_DISPLAY)
+ Display *display = static_cast<Display *>(dpy);
+ if (dpy == EGL_NO_DISPLAY || !Display::isValidDisplay(display))
{
SetGlobalError(Error(EGL_BAD_DISPLAY));
return EGL_FALSE;
}
- Display *display = static_cast<Display*>(dpy);
-
Error error = display->initialize();
if (error.isError())
{
@@ -74,13 +74,13 @@ EGLBoolean EGLAPIENTRY Terminate(EGLDisplay dpy)
{
EVENT("(EGLDisplay dpy = 0x%0.8p)", dpy);
- if (dpy == EGL_NO_DISPLAY)
+ Display *display = static_cast<Display *>(dpy);
+ if (dpy == EGL_NO_DISPLAY || !Display::isValidDisplay(display))
{
SetGlobalError(Error(EGL_BAD_DISPLAY));
return EGL_FALSE;
}
- Display *display = static_cast<Display*>(dpy);
gl::Context *context = GetGlobalContext();
if (display->isValidContext(context))
@@ -171,7 +171,7 @@ EGLBoolean EGLAPIENTRY GetConfigs(EGLDisplay dpy, EGLConfig *configs, EGLint con
configs[i] = const_cast<Config*>(filteredConfigs[i]);
}
}
- *num_config = filteredConfigs.size();
+ *num_config = static_cast<EGLint>(filteredConfigs.size());
SetGlobalError(Error(EGL_SUCCESS));
return EGL_TRUE;
@@ -207,7 +207,7 @@ EGLBoolean EGLAPIENTRY ChooseConfig(EGLDisplay dpy, const EGLint *attrib_list, E
configs[i] = const_cast<Config*>(filteredConfigs[i]);
}
}
- *num_config = filteredConfigs.size();
+ *num_config = static_cast<EGLint>(filteredConfigs.size());
SetGlobalError(Error(EGL_SUCCESS));
return EGL_TRUE;
@@ -426,6 +426,37 @@ EGLBoolean EGLAPIENTRY QuerySurface(EGLDisplay dpy, EGLSurface surface, EGLint a
}
*value = eglSurface->isFixedSize();
break;
+ case EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE:
+ if (!display->getExtensions().flexibleSurfaceCompatibility)
+ {
+ SetGlobalError(
+ Error(EGL_BAD_ATTRIBUTE,
+ "EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE cannot be used without "
+ "EGL_ANGLE_flexible_surface_compatibility support."));
+ return EGL_FALSE;
+ }
+ *value = eglSurface->flexibleSurfaceCompatibilityRequested();
+ break;
+ case EGL_SURFACE_ORIENTATION_ANGLE:
+ if (!display->getExtensions().surfaceOrientation)
+ {
+ SetGlobalError(Error(EGL_BAD_ATTRIBUTE,
+ "EGL_SURFACE_ORIENTATION_ANGLE cannot be queried without "
+ "EGL_ANGLE_surface_orientation support."));
+ return EGL_FALSE;
+ }
+ *value = eglSurface->getOrientation();
+ break;
+ case EGL_DIRECT_COMPOSITION_ANGLE:
+ if (!display->getExtensions().directComposition)
+ {
+ SetGlobalError(Error(EGL_BAD_ATTRIBUTE,
+ "EGL_DIRECT_COMPOSITION_ANGLE cannot be used without "
+ "EGL_ANGLE_direct_composition support."));
+ return EGL_FALSE;
+ }
+ *value = eglSurface->directComposition();
+ break;
default:
SetGlobalError(Error(EGL_BAD_ATTRIBUTE));
return EGL_FALSE;
@@ -504,14 +535,42 @@ EGLBoolean EGLAPIENTRY MakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface r
Display *display = static_cast<Display*>(dpy);
gl::Context *context = static_cast<gl::Context*>(ctx);
- bool noContext = (ctx == EGL_NO_CONTEXT);
- bool noSurface = (draw == EGL_NO_SURFACE || read == EGL_NO_SURFACE);
- if (noContext != noSurface)
+ // If ctx is EGL_NO_CONTEXT and either draw or read are not EGL_NO_SURFACE, an EGL_BAD_MATCH
+ // error is generated.
+ if (ctx == EGL_NO_CONTEXT && (draw != EGL_NO_SURFACE || read != EGL_NO_SURFACE))
{
SetGlobalError(Error(EGL_BAD_MATCH));
return EGL_FALSE;
}
+ if (ctx != EGL_NO_CONTEXT && draw == EGL_NO_SURFACE && read == EGL_NO_SURFACE)
+ {
+ SetGlobalError(Error(EGL_BAD_MATCH));
+ return EGL_FALSE;
+ }
+
+ // If either of draw or read is a valid surface and the other is EGL_NO_SURFACE, an
+ // EGL_BAD_MATCH error is generated.
+ if ((read == EGL_NO_SURFACE) != (draw == EGL_NO_SURFACE))
+ {
+ SetGlobalError(Error(
+ EGL_BAD_MATCH, "read and draw must both be valid surfaces, or both be EGL_NO_SURFACE"));
+ return EGL_FALSE;
+ }
+
+ if (dpy == EGL_NO_DISPLAY || !Display::isValidDisplay(display))
+ {
+ SetGlobalError(Error(EGL_BAD_DISPLAY, "'dpy' not a valid EGLDisplay handle"));
+ return EGL_FALSE;
+ }
+
+ // EGL 1.5 spec: dpy can be uninitialized if all other parameters are null
+ if (!display->isInitialized() && (ctx != EGL_NO_CONTEXT || draw != EGL_NO_SURFACE || read != EGL_NO_SURFACE))
+ {
+ SetGlobalError(Error(EGL_NOT_INITIALIZED, "'dpy' not initialized"));
+ return EGL_FALSE;
+ }
+
if (ctx != EGL_NO_CONTEXT)
{
Error error = ValidateContext(display, context);
@@ -522,7 +581,7 @@ EGLBoolean EGLAPIENTRY MakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface r
}
}
- if (dpy != EGL_NO_DISPLAY && display->isInitialized())
+ if (display->isInitialized())
{
if (display->testDeviceLost())
{
@@ -559,19 +618,54 @@ EGLBoolean EGLAPIENTRY MakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface r
}
}
+ if (readSurface)
+ {
+ Error readCompatError =
+ ValidateCompatibleConfigs(display, readSurface->getConfig(), readSurface,
+ context->getConfig(), readSurface->getType());
+ if (readCompatError.isError())
+ {
+ SetGlobalError(readCompatError);
+ return EGL_FALSE;
+ }
+ }
+
if (draw != read)
{
UNIMPLEMENTED(); // FIXME
+
+ if (drawSurface)
+ {
+ Error drawCompatError =
+ ValidateCompatibleConfigs(display, drawSurface->getConfig(), drawSurface,
+ context->getConfig(), drawSurface->getType());
+ if (drawCompatError.isError())
+ {
+ SetGlobalError(drawCompatError);
+ return EGL_FALSE;
+ }
+ }
+ }
+
+ Error makeCurrentError = display->makeCurrent(drawSurface, readSurface, context);
+ if (makeCurrentError.isError())
+ {
+ SetGlobalError(makeCurrentError);
+ return EGL_FALSE;
}
+ gl::Context *previousContext = GetGlobalContext();
+
SetGlobalDisplay(display);
SetGlobalDrawSurface(drawSurface);
SetGlobalReadSurface(readSurface);
SetGlobalContext(context);
- if (context != nullptr && display != nullptr && drawSurface != nullptr)
+ // Release the surface from the previously-current context, to allow
+ // destroyed surfaces to delete themselves.
+ if (previousContext != nullptr && context != previousContext)
{
- display->makeCurrent(drawSurface, readSurface, context);
+ previousContext->releaseSurface();
}
SetGlobalError(Error(EGL_SUCCESS));
@@ -627,7 +721,7 @@ EGLBoolean EGLAPIENTRY QueryContext(EGLDisplay dpy, EGLContext ctx, EGLint attri
switch (attribute)
{
case EGL_CONFIG_ID:
- *value = context->getConfigID();
+ *value = context->getConfig()->configID;
break;
case EGL_CONTEXT_CLIENT_TYPE:
*value = context->getClientType();
@@ -651,20 +745,56 @@ EGLBoolean EGLAPIENTRY WaitGL(void)
{
EVENT("()");
- UNIMPLEMENTED(); // FIXME
+ Display *display = GetGlobalDisplay();
+
+ Error error = ValidateDisplay(display);
+ if (error.isError())
+ {
+ SetGlobalError(error);
+ return EGL_FALSE;
+ }
+
+ // eglWaitGL like calling eglWaitClient with the OpenGL ES API bound. Since we only implement
+ // OpenGL ES we can do the call directly.
+ error = display->waitClient();
+ if (error.isError())
+ {
+ SetGlobalError(error);
+ return EGL_FALSE;
+ }
SetGlobalError(Error(EGL_SUCCESS));
- return 0;
+ return EGL_TRUE;
}
EGLBoolean EGLAPIENTRY WaitNative(EGLint engine)
{
EVENT("(EGLint engine = %d)", engine);
- UNIMPLEMENTED(); // FIXME
+ Display *display = GetGlobalDisplay();
+
+ Error error = ValidateDisplay(display);
+ if (error.isError())
+ {
+ SetGlobalError(error);
+ return EGL_FALSE;
+ }
+
+ if (engine != EGL_CORE_NATIVE_ENGINE)
+ {
+ SetGlobalError(
+ Error(EGL_BAD_PARAMETER, "the 'engine' parameter has an unrecognized value"));
+ }
+
+ error = display->waitNative(engine, GetGlobalDrawSurface(), GetGlobalReadSurface());
+ if (error.isError())
+ {
+ SetGlobalError(error);
+ return EGL_FALSE;
+ }
SetGlobalError(Error(EGL_SUCCESS));
- return 0;
+ return EGL_TRUE;
}
EGLBoolean EGLAPIENTRY SwapBuffers(EGLDisplay dpy, EGLSurface surface)
@@ -775,13 +905,18 @@ EGLBoolean EGLAPIENTRY BindTexImage(EGLDisplay dpy, EGLSurface surface, EGLint b
gl::Texture *textureObject = context->getTargetTexture(GL_TEXTURE_2D);
ASSERT(textureObject != NULL);
- if (textureObject->isImmutable())
+ if (textureObject->getImmutableFormat())
{
SetGlobalError(Error(EGL_BAD_MATCH));
return EGL_FALSE;
}
- eglSurface->bindTexImage(textureObject, buffer);
+ error = eglSurface->bindTexImage(textureObject, buffer);
+ if (error.isError())
+ {
+ SetGlobalError(error);
+ return EGL_FALSE;
+ }
}
SetGlobalError(Error(EGL_SUCCESS));
@@ -845,7 +980,12 @@ EGLBoolean EGLAPIENTRY ReleaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLin
if (texture)
{
- eglSurface->releaseTexImage(buffer);
+ error = eglSurface->releaseTexImage(buffer);
+ if (error.isError())
+ {
+ SetGlobalError(error);
+ return EGL_FALSE;
+ }
}
SetGlobalError(Error(EGL_SUCCESS));
@@ -959,10 +1099,24 @@ EGLBoolean EGLAPIENTRY WaitClient(void)
{
EVENT("()");
- UNIMPLEMENTED(); // FIXME
+ Display *display = GetGlobalDisplay();
+
+ Error error = ValidateDisplay(display);
+ if (error.isError())
+ {
+ SetGlobalError(error);
+ return EGL_FALSE;
+ }
+
+ error = display->waitClient();
+ if (error.isError())
+ {
+ SetGlobalError(error);
+ return EGL_FALSE;
+ }
SetGlobalError(Error(EGL_SUCCESS));
- return 0;
+ return EGL_TRUE;
}
// EGL 1.4
@@ -1066,62 +1220,443 @@ __eglMustCastToProperFunctionPointerType EGLAPIENTRY GetProcAddress(const char *
{
EVENT("(const char *procname = \"%s\")", procname);
- struct Extension
- {
- const char *name;
- __eglMustCastToProperFunctionPointerType address;
+ typedef std::map<std::string, __eglMustCastToProperFunctionPointerType> ProcAddressMap;
+ auto generateProcAddressMap = []()
+ {
+ ProcAddressMap map;
+#define INSERT_PROC_ADDRESS(ns, proc) \
+ map[#ns #proc] = reinterpret_cast<__eglMustCastToProperFunctionPointerType>(ns::proc)
+
+ // GLES2 core
+ INSERT_PROC_ADDRESS(gl, ActiveTexture);
+ INSERT_PROC_ADDRESS(gl, AttachShader);
+ INSERT_PROC_ADDRESS(gl, BindAttribLocation);
+ INSERT_PROC_ADDRESS(gl, BindBuffer);
+ INSERT_PROC_ADDRESS(gl, BindFramebuffer);
+ INSERT_PROC_ADDRESS(gl, BindRenderbuffer);
+ INSERT_PROC_ADDRESS(gl, BindTexture);
+ INSERT_PROC_ADDRESS(gl, BlendColor);
+ INSERT_PROC_ADDRESS(gl, BlendEquation);
+ INSERT_PROC_ADDRESS(gl, BlendEquationSeparate);
+ INSERT_PROC_ADDRESS(gl, BlendFunc);
+ INSERT_PROC_ADDRESS(gl, BlendFuncSeparate);
+ INSERT_PROC_ADDRESS(gl, BufferData);
+ INSERT_PROC_ADDRESS(gl, BufferSubData);
+ INSERT_PROC_ADDRESS(gl, CheckFramebufferStatus);
+ INSERT_PROC_ADDRESS(gl, Clear);
+ INSERT_PROC_ADDRESS(gl, ClearColor);
+ INSERT_PROC_ADDRESS(gl, ClearDepthf);
+ INSERT_PROC_ADDRESS(gl, ClearStencil);
+ INSERT_PROC_ADDRESS(gl, ColorMask);
+ INSERT_PROC_ADDRESS(gl, CompileShader);
+ INSERT_PROC_ADDRESS(gl, CompressedTexImage2D);
+ INSERT_PROC_ADDRESS(gl, CompressedTexSubImage2D);
+ INSERT_PROC_ADDRESS(gl, CopyTexImage2D);
+ INSERT_PROC_ADDRESS(gl, CopyTexSubImage2D);
+ INSERT_PROC_ADDRESS(gl, CreateProgram);
+ INSERT_PROC_ADDRESS(gl, CreateShader);
+ INSERT_PROC_ADDRESS(gl, CullFace);
+ INSERT_PROC_ADDRESS(gl, DeleteBuffers);
+ INSERT_PROC_ADDRESS(gl, DeleteFramebuffers);
+ INSERT_PROC_ADDRESS(gl, DeleteProgram);
+ INSERT_PROC_ADDRESS(gl, DeleteRenderbuffers);
+ INSERT_PROC_ADDRESS(gl, DeleteShader);
+ INSERT_PROC_ADDRESS(gl, DeleteTextures);
+ INSERT_PROC_ADDRESS(gl, DepthFunc);
+ INSERT_PROC_ADDRESS(gl, DepthMask);
+ INSERT_PROC_ADDRESS(gl, DepthRangef);
+ INSERT_PROC_ADDRESS(gl, DetachShader);
+ INSERT_PROC_ADDRESS(gl, Disable);
+ INSERT_PROC_ADDRESS(gl, DisableVertexAttribArray);
+ INSERT_PROC_ADDRESS(gl, DrawArrays);
+ INSERT_PROC_ADDRESS(gl, DrawElements);
+ INSERT_PROC_ADDRESS(gl, Enable);
+ INSERT_PROC_ADDRESS(gl, EnableVertexAttribArray);
+ INSERT_PROC_ADDRESS(gl, Finish);
+ INSERT_PROC_ADDRESS(gl, Flush);
+ INSERT_PROC_ADDRESS(gl, FramebufferRenderbuffer);
+ INSERT_PROC_ADDRESS(gl, FramebufferTexture2D);
+ INSERT_PROC_ADDRESS(gl, FrontFace);
+ INSERT_PROC_ADDRESS(gl, GenBuffers);
+ INSERT_PROC_ADDRESS(gl, GenerateMipmap);
+ INSERT_PROC_ADDRESS(gl, GenFramebuffers);
+ INSERT_PROC_ADDRESS(gl, GenRenderbuffers);
+ INSERT_PROC_ADDRESS(gl, GenTextures);
+ INSERT_PROC_ADDRESS(gl, GetActiveAttrib);
+ INSERT_PROC_ADDRESS(gl, GetActiveUniform);
+ INSERT_PROC_ADDRESS(gl, GetAttachedShaders);
+ INSERT_PROC_ADDRESS(gl, GetAttribLocation);
+ INSERT_PROC_ADDRESS(gl, GetBooleanv);
+ INSERT_PROC_ADDRESS(gl, GetBufferParameteriv);
+ INSERT_PROC_ADDRESS(gl, GetError);
+ INSERT_PROC_ADDRESS(gl, GetFloatv);
+ INSERT_PROC_ADDRESS(gl, GetFramebufferAttachmentParameteriv);
+ INSERT_PROC_ADDRESS(gl, GetIntegerv);
+ INSERT_PROC_ADDRESS(gl, GetProgramiv);
+ INSERT_PROC_ADDRESS(gl, GetProgramInfoLog);
+ INSERT_PROC_ADDRESS(gl, GetRenderbufferParameteriv);
+ INSERT_PROC_ADDRESS(gl, GetShaderiv);
+ INSERT_PROC_ADDRESS(gl, GetShaderInfoLog);
+ INSERT_PROC_ADDRESS(gl, GetShaderPrecisionFormat);
+ INSERT_PROC_ADDRESS(gl, GetShaderSource);
+ INSERT_PROC_ADDRESS(gl, GetString);
+ INSERT_PROC_ADDRESS(gl, GetTexParameterfv);
+ INSERT_PROC_ADDRESS(gl, GetTexParameteriv);
+ INSERT_PROC_ADDRESS(gl, GetUniformfv);
+ INSERT_PROC_ADDRESS(gl, GetUniformiv);
+ INSERT_PROC_ADDRESS(gl, GetUniformLocation);
+ INSERT_PROC_ADDRESS(gl, GetVertexAttribfv);
+ INSERT_PROC_ADDRESS(gl, GetVertexAttribiv);
+ INSERT_PROC_ADDRESS(gl, GetVertexAttribPointerv);
+ INSERT_PROC_ADDRESS(gl, Hint);
+ INSERT_PROC_ADDRESS(gl, IsBuffer);
+ INSERT_PROC_ADDRESS(gl, IsEnabled);
+ INSERT_PROC_ADDRESS(gl, IsFramebuffer);
+ INSERT_PROC_ADDRESS(gl, IsProgram);
+ INSERT_PROC_ADDRESS(gl, IsRenderbuffer);
+ INSERT_PROC_ADDRESS(gl, IsShader);
+ INSERT_PROC_ADDRESS(gl, IsTexture);
+ INSERT_PROC_ADDRESS(gl, LineWidth);
+ INSERT_PROC_ADDRESS(gl, LinkProgram);
+ INSERT_PROC_ADDRESS(gl, PixelStorei);
+ INSERT_PROC_ADDRESS(gl, PolygonOffset);
+ INSERT_PROC_ADDRESS(gl, ReadPixels);
+ INSERT_PROC_ADDRESS(gl, ReleaseShaderCompiler);
+ INSERT_PROC_ADDRESS(gl, RenderbufferStorage);
+ INSERT_PROC_ADDRESS(gl, SampleCoverage);
+ INSERT_PROC_ADDRESS(gl, Scissor);
+ INSERT_PROC_ADDRESS(gl, ShaderBinary);
+ INSERT_PROC_ADDRESS(gl, ShaderSource);
+ INSERT_PROC_ADDRESS(gl, StencilFunc);
+ INSERT_PROC_ADDRESS(gl, StencilFuncSeparate);
+ INSERT_PROC_ADDRESS(gl, StencilMask);
+ INSERT_PROC_ADDRESS(gl, StencilMaskSeparate);
+ INSERT_PROC_ADDRESS(gl, StencilOp);
+ INSERT_PROC_ADDRESS(gl, StencilOpSeparate);
+ INSERT_PROC_ADDRESS(gl, TexImage2D);
+ INSERT_PROC_ADDRESS(gl, TexParameterf);
+ INSERT_PROC_ADDRESS(gl, TexParameterfv);
+ INSERT_PROC_ADDRESS(gl, TexParameteri);
+ INSERT_PROC_ADDRESS(gl, TexParameteriv);
+ INSERT_PROC_ADDRESS(gl, TexSubImage2D);
+ INSERT_PROC_ADDRESS(gl, Uniform1f);
+ INSERT_PROC_ADDRESS(gl, Uniform1fv);
+ INSERT_PROC_ADDRESS(gl, Uniform1i);
+ INSERT_PROC_ADDRESS(gl, Uniform1iv);
+ INSERT_PROC_ADDRESS(gl, Uniform2f);
+ INSERT_PROC_ADDRESS(gl, Uniform2fv);
+ INSERT_PROC_ADDRESS(gl, Uniform2i);
+ INSERT_PROC_ADDRESS(gl, Uniform2iv);
+ INSERT_PROC_ADDRESS(gl, Uniform3f);
+ INSERT_PROC_ADDRESS(gl, Uniform3fv);
+ INSERT_PROC_ADDRESS(gl, Uniform3i);
+ INSERT_PROC_ADDRESS(gl, Uniform3iv);
+ INSERT_PROC_ADDRESS(gl, Uniform4f);
+ INSERT_PROC_ADDRESS(gl, Uniform4fv);
+ INSERT_PROC_ADDRESS(gl, Uniform4i);
+ INSERT_PROC_ADDRESS(gl, Uniform4iv);
+ INSERT_PROC_ADDRESS(gl, UniformMatrix2fv);
+ INSERT_PROC_ADDRESS(gl, UniformMatrix3fv);
+ INSERT_PROC_ADDRESS(gl, UniformMatrix4fv);
+ INSERT_PROC_ADDRESS(gl, UseProgram);
+ INSERT_PROC_ADDRESS(gl, ValidateProgram);
+ INSERT_PROC_ADDRESS(gl, VertexAttrib1f);
+ INSERT_PROC_ADDRESS(gl, VertexAttrib1fv);
+ INSERT_PROC_ADDRESS(gl, VertexAttrib2f);
+ INSERT_PROC_ADDRESS(gl, VertexAttrib2fv);
+ INSERT_PROC_ADDRESS(gl, VertexAttrib3f);
+ INSERT_PROC_ADDRESS(gl, VertexAttrib3fv);
+ INSERT_PROC_ADDRESS(gl, VertexAttrib4f);
+ INSERT_PROC_ADDRESS(gl, VertexAttrib4fv);
+ INSERT_PROC_ADDRESS(gl, VertexAttribPointer);
+ INSERT_PROC_ADDRESS(gl, Viewport);
+
+ // GL_ANGLE_framebuffer_blit
+ INSERT_PROC_ADDRESS(gl, BlitFramebufferANGLE);
+
+ // GL_ANGLE_framebuffer_multisample
+ INSERT_PROC_ADDRESS(gl, RenderbufferStorageMultisampleANGLE);
+
+ // GL_EXT_discard_framebuffer
+ INSERT_PROC_ADDRESS(gl, DiscardFramebufferEXT);
+
+ // GL_NV_fence
+ INSERT_PROC_ADDRESS(gl, DeleteFencesNV);
+ INSERT_PROC_ADDRESS(gl, GenFencesNV);
+ INSERT_PROC_ADDRESS(gl, IsFenceNV);
+ INSERT_PROC_ADDRESS(gl, TestFenceNV);
+ INSERT_PROC_ADDRESS(gl, GetFenceivNV);
+ INSERT_PROC_ADDRESS(gl, FinishFenceNV);
+ INSERT_PROC_ADDRESS(gl, SetFenceNV);
+
+ // GL_ANGLE_translated_shader_source
+ INSERT_PROC_ADDRESS(gl, GetTranslatedShaderSourceANGLE);
+
+ // GL_EXT_texture_storage
+ INSERT_PROC_ADDRESS(gl, TexStorage2DEXT);
+
+ // GL_EXT_robustness
+ INSERT_PROC_ADDRESS(gl, GetGraphicsResetStatusEXT);
+ INSERT_PROC_ADDRESS(gl, ReadnPixelsEXT);
+ INSERT_PROC_ADDRESS(gl, GetnUniformfvEXT);
+ INSERT_PROC_ADDRESS(gl, GetnUniformivEXT);
+
+ // GL_EXT_occlusion_query_boolean
+ INSERT_PROC_ADDRESS(gl, GenQueriesEXT);
+ INSERT_PROC_ADDRESS(gl, DeleteQueriesEXT);
+ INSERT_PROC_ADDRESS(gl, IsQueryEXT);
+ INSERT_PROC_ADDRESS(gl, BeginQueryEXT);
+ INSERT_PROC_ADDRESS(gl, EndQueryEXT);
+ INSERT_PROC_ADDRESS(gl, GetQueryivEXT);
+ INSERT_PROC_ADDRESS(gl, GetQueryObjectuivEXT);
+
+ // GL_EXT_draw_buffers
+ INSERT_PROC_ADDRESS(gl, DrawBuffersEXT);
+
+ // GL_ANGLE_instanced_arrays
+ INSERT_PROC_ADDRESS(gl, DrawArraysInstancedANGLE);
+ INSERT_PROC_ADDRESS(gl, DrawElementsInstancedANGLE);
+ INSERT_PROC_ADDRESS(gl, VertexAttribDivisorANGLE);
+
+ // GL_OES_get_program_binary
+ INSERT_PROC_ADDRESS(gl, GetProgramBinaryOES);
+ INSERT_PROC_ADDRESS(gl, ProgramBinaryOES);
+
+ // GL_OES_mapbuffer
+ INSERT_PROC_ADDRESS(gl, MapBufferOES);
+ INSERT_PROC_ADDRESS(gl, UnmapBufferOES);
+ INSERT_PROC_ADDRESS(gl, GetBufferPointervOES);
+
+ // GL_EXT_map_buffer_range
+ INSERT_PROC_ADDRESS(gl, MapBufferRangeEXT);
+ INSERT_PROC_ADDRESS(gl, FlushMappedBufferRangeEXT);
+
+ // GL_EXT_debug_marker
+ INSERT_PROC_ADDRESS(gl, InsertEventMarkerEXT);
+ INSERT_PROC_ADDRESS(gl, PushGroupMarkerEXT);
+ INSERT_PROC_ADDRESS(gl, PopGroupMarkerEXT);
+
+ // GL_OES_EGL_image
+ INSERT_PROC_ADDRESS(gl, EGLImageTargetTexture2DOES);
+ INSERT_PROC_ADDRESS(gl, EGLImageTargetRenderbufferStorageOES);
+
+ // GL_OES_vertex_array_object
+ INSERT_PROC_ADDRESS(gl, BindVertexArrayOES);
+ INSERT_PROC_ADDRESS(gl, DeleteVertexArraysOES);
+ INSERT_PROC_ADDRESS(gl, GenVertexArraysOES);
+ INSERT_PROC_ADDRESS(gl, IsVertexArrayOES);
+
+ // GL_KHR_debug
+ INSERT_PROC_ADDRESS(gl, DebugMessageControlKHR);
+ INSERT_PROC_ADDRESS(gl, DebugMessageInsertKHR);
+ INSERT_PROC_ADDRESS(gl, DebugMessageCallbackKHR);
+ INSERT_PROC_ADDRESS(gl, GetDebugMessageLogKHR);
+ INSERT_PROC_ADDRESS(gl, PushDebugGroupKHR);
+ INSERT_PROC_ADDRESS(gl, PopDebugGroupKHR);
+ INSERT_PROC_ADDRESS(gl, ObjectLabelKHR);
+ INSERT_PROC_ADDRESS(gl, GetObjectLabelKHR);
+ INSERT_PROC_ADDRESS(gl, ObjectPtrLabelKHR);
+ INSERT_PROC_ADDRESS(gl, GetObjectPtrLabelKHR);
+ INSERT_PROC_ADDRESS(gl, GetPointervKHR);
+
+ // GLES3 core
+ INSERT_PROC_ADDRESS(gl, ReadBuffer);
+ INSERT_PROC_ADDRESS(gl, DrawRangeElements);
+ INSERT_PROC_ADDRESS(gl, TexImage3D);
+ INSERT_PROC_ADDRESS(gl, TexSubImage3D);
+ INSERT_PROC_ADDRESS(gl, CopyTexSubImage3D);
+ INSERT_PROC_ADDRESS(gl, CompressedTexImage3D);
+ INSERT_PROC_ADDRESS(gl, CompressedTexSubImage3D);
+ INSERT_PROC_ADDRESS(gl, GenQueries);
+ INSERT_PROC_ADDRESS(gl, DeleteQueries);
+ INSERT_PROC_ADDRESS(gl, IsQuery);
+ INSERT_PROC_ADDRESS(gl, BeginQuery);
+ INSERT_PROC_ADDRESS(gl, EndQuery);
+ INSERT_PROC_ADDRESS(gl, GetQueryiv);
+ INSERT_PROC_ADDRESS(gl, GetQueryObjectuiv);
+ INSERT_PROC_ADDRESS(gl, UnmapBuffer);
+ INSERT_PROC_ADDRESS(gl, GetBufferPointerv);
+ INSERT_PROC_ADDRESS(gl, DrawBuffers);
+ INSERT_PROC_ADDRESS(gl, UniformMatrix2x3fv);
+ INSERT_PROC_ADDRESS(gl, UniformMatrix3x2fv);
+ INSERT_PROC_ADDRESS(gl, UniformMatrix2x4fv);
+ INSERT_PROC_ADDRESS(gl, UniformMatrix4x2fv);
+ INSERT_PROC_ADDRESS(gl, UniformMatrix3x4fv);
+ INSERT_PROC_ADDRESS(gl, UniformMatrix4x3fv);
+ INSERT_PROC_ADDRESS(gl, BlitFramebuffer);
+ INSERT_PROC_ADDRESS(gl, RenderbufferStorageMultisample);
+ INSERT_PROC_ADDRESS(gl, FramebufferTextureLayer);
+ INSERT_PROC_ADDRESS(gl, MapBufferRange);
+ INSERT_PROC_ADDRESS(gl, FlushMappedBufferRange);
+ INSERT_PROC_ADDRESS(gl, BindVertexArray);
+ INSERT_PROC_ADDRESS(gl, DeleteVertexArrays);
+ INSERT_PROC_ADDRESS(gl, GenVertexArrays);
+ INSERT_PROC_ADDRESS(gl, IsVertexArray);
+ INSERT_PROC_ADDRESS(gl, GetIntegeri_v);
+ INSERT_PROC_ADDRESS(gl, BeginTransformFeedback);
+ INSERT_PROC_ADDRESS(gl, EndTransformFeedback);
+ INSERT_PROC_ADDRESS(gl, BindBufferRange);
+ INSERT_PROC_ADDRESS(gl, BindBufferBase);
+ INSERT_PROC_ADDRESS(gl, TransformFeedbackVaryings);
+ INSERT_PROC_ADDRESS(gl, GetTransformFeedbackVarying);
+ INSERT_PROC_ADDRESS(gl, VertexAttribIPointer);
+ INSERT_PROC_ADDRESS(gl, GetVertexAttribIiv);
+ INSERT_PROC_ADDRESS(gl, GetVertexAttribIuiv);
+ INSERT_PROC_ADDRESS(gl, VertexAttribI4i);
+ INSERT_PROC_ADDRESS(gl, VertexAttribI4ui);
+ INSERT_PROC_ADDRESS(gl, VertexAttribI4iv);
+ INSERT_PROC_ADDRESS(gl, VertexAttribI4uiv);
+ INSERT_PROC_ADDRESS(gl, GetUniformuiv);
+ INSERT_PROC_ADDRESS(gl, GetFragDataLocation);
+ INSERT_PROC_ADDRESS(gl, Uniform1ui);
+ INSERT_PROC_ADDRESS(gl, Uniform2ui);
+ INSERT_PROC_ADDRESS(gl, Uniform3ui);
+ INSERT_PROC_ADDRESS(gl, Uniform4ui);
+ INSERT_PROC_ADDRESS(gl, Uniform1uiv);
+ INSERT_PROC_ADDRESS(gl, Uniform2uiv);
+ INSERT_PROC_ADDRESS(gl, Uniform3uiv);
+ INSERT_PROC_ADDRESS(gl, Uniform4uiv);
+ INSERT_PROC_ADDRESS(gl, ClearBufferiv);
+ INSERT_PROC_ADDRESS(gl, ClearBufferuiv);
+ INSERT_PROC_ADDRESS(gl, ClearBufferfv);
+ INSERT_PROC_ADDRESS(gl, ClearBufferfi);
+ INSERT_PROC_ADDRESS(gl, GetStringi);
+ INSERT_PROC_ADDRESS(gl, CopyBufferSubData);
+ INSERT_PROC_ADDRESS(gl, GetUniformIndices);
+ INSERT_PROC_ADDRESS(gl, GetActiveUniformsiv);
+ INSERT_PROC_ADDRESS(gl, GetUniformBlockIndex);
+ INSERT_PROC_ADDRESS(gl, GetActiveUniformBlockiv);
+ INSERT_PROC_ADDRESS(gl, GetActiveUniformBlockName);
+ INSERT_PROC_ADDRESS(gl, UniformBlockBinding);
+ INSERT_PROC_ADDRESS(gl, DrawArraysInstanced);
+ INSERT_PROC_ADDRESS(gl, DrawElementsInstanced);
+ map["glFenceSync"] =
+ reinterpret_cast<__eglMustCastToProperFunctionPointerType>(gl::FenceSync_);
+ INSERT_PROC_ADDRESS(gl, IsSync);
+ INSERT_PROC_ADDRESS(gl, DeleteSync);
+ INSERT_PROC_ADDRESS(gl, ClientWaitSync);
+ INSERT_PROC_ADDRESS(gl, WaitSync);
+ INSERT_PROC_ADDRESS(gl, GetInteger64v);
+ INSERT_PROC_ADDRESS(gl, GetSynciv);
+ INSERT_PROC_ADDRESS(gl, GetInteger64i_v);
+ INSERT_PROC_ADDRESS(gl, GetBufferParameteri64v);
+ INSERT_PROC_ADDRESS(gl, GenSamplers);
+ INSERT_PROC_ADDRESS(gl, DeleteSamplers);
+ INSERT_PROC_ADDRESS(gl, IsSampler);
+ INSERT_PROC_ADDRESS(gl, BindSampler);
+ INSERT_PROC_ADDRESS(gl, SamplerParameteri);
+ INSERT_PROC_ADDRESS(gl, SamplerParameteriv);
+ INSERT_PROC_ADDRESS(gl, SamplerParameterf);
+ INSERT_PROC_ADDRESS(gl, SamplerParameterfv);
+ INSERT_PROC_ADDRESS(gl, GetSamplerParameteriv);
+ INSERT_PROC_ADDRESS(gl, GetSamplerParameterfv);
+ INSERT_PROC_ADDRESS(gl, VertexAttribDivisor);
+ INSERT_PROC_ADDRESS(gl, BindTransformFeedback);
+ INSERT_PROC_ADDRESS(gl, DeleteTransformFeedbacks);
+ INSERT_PROC_ADDRESS(gl, GenTransformFeedbacks);
+ INSERT_PROC_ADDRESS(gl, IsTransformFeedback);
+ INSERT_PROC_ADDRESS(gl, PauseTransformFeedback);
+ INSERT_PROC_ADDRESS(gl, ResumeTransformFeedback);
+ INSERT_PROC_ADDRESS(gl, GetProgramBinary);
+ INSERT_PROC_ADDRESS(gl, ProgramBinary);
+ INSERT_PROC_ADDRESS(gl, ProgramParameteri);
+ INSERT_PROC_ADDRESS(gl, InvalidateFramebuffer);
+ INSERT_PROC_ADDRESS(gl, InvalidateSubFramebuffer);
+ INSERT_PROC_ADDRESS(gl, TexStorage2D);
+ INSERT_PROC_ADDRESS(gl, TexStorage3D);
+ INSERT_PROC_ADDRESS(gl, GetInternalformativ);
+
+ // EGL 1.0
+ INSERT_PROC_ADDRESS(egl, ChooseConfig);
+ INSERT_PROC_ADDRESS(egl, CopyBuffers);
+ INSERT_PROC_ADDRESS(egl, CreateContext);
+ INSERT_PROC_ADDRESS(egl, CreatePbufferSurface);
+ INSERT_PROC_ADDRESS(egl, CreatePixmapSurface);
+ INSERT_PROC_ADDRESS(egl, CreateWindowSurface);
+ INSERT_PROC_ADDRESS(egl, DestroyContext);
+ INSERT_PROC_ADDRESS(egl, DestroySurface);
+ INSERT_PROC_ADDRESS(egl, GetConfigAttrib);
+ INSERT_PROC_ADDRESS(egl, GetConfigs);
+ INSERT_PROC_ADDRESS(egl, GetCurrentDisplay);
+ INSERT_PROC_ADDRESS(egl, GetCurrentSurface);
+ INSERT_PROC_ADDRESS(egl, GetDisplay);
+ INSERT_PROC_ADDRESS(egl, GetError);
+ INSERT_PROC_ADDRESS(egl, GetProcAddress);
+ INSERT_PROC_ADDRESS(egl, Initialize);
+ INSERT_PROC_ADDRESS(egl, MakeCurrent);
+ INSERT_PROC_ADDRESS(egl, QueryContext);
+ INSERT_PROC_ADDRESS(egl, QueryString);
+ INSERT_PROC_ADDRESS(egl, QuerySurface);
+ INSERT_PROC_ADDRESS(egl, SwapBuffers);
+ INSERT_PROC_ADDRESS(egl, Terminate);
+ INSERT_PROC_ADDRESS(egl, WaitGL);
+ INSERT_PROC_ADDRESS(egl, WaitNative);
+
+ // EGL 1.1
+ INSERT_PROC_ADDRESS(egl, BindTexImage);
+ INSERT_PROC_ADDRESS(egl, ReleaseTexImage);
+ INSERT_PROC_ADDRESS(egl, SurfaceAttrib);
+ INSERT_PROC_ADDRESS(egl, SwapInterval);
+
+ // EGL 1.2
+ INSERT_PROC_ADDRESS(egl, BindAPI);
+ INSERT_PROC_ADDRESS(egl, QueryAPI);
+ INSERT_PROC_ADDRESS(egl, CreatePbufferFromClientBuffer);
+ INSERT_PROC_ADDRESS(egl, ReleaseThread);
+ INSERT_PROC_ADDRESS(egl, WaitClient);
+
+ // EGL 1.4
+ INSERT_PROC_ADDRESS(egl, GetCurrentContext);
+
+ // EGL 1.5
+ INSERT_PROC_ADDRESS(egl, CreateSync);
+ INSERT_PROC_ADDRESS(egl, DestroySync);
+ INSERT_PROC_ADDRESS(egl, ClientWaitSync);
+ INSERT_PROC_ADDRESS(egl, GetSyncAttrib);
+ INSERT_PROC_ADDRESS(egl, CreateImage);
+ INSERT_PROC_ADDRESS(egl, DestroyImage);
+ INSERT_PROC_ADDRESS(egl, GetPlatformDisplay);
+ INSERT_PROC_ADDRESS(egl, CreatePlatformWindowSurface);
+ INSERT_PROC_ADDRESS(egl, CreatePlatformPixmapSurface);
+ INSERT_PROC_ADDRESS(egl, WaitSync);
+
+ // EGL_ANGLE_query_surface_pointer
+ INSERT_PROC_ADDRESS(egl, QuerySurfacePointerANGLE);
+
+ // EGL_NV_post_sub_buffer
+ INSERT_PROC_ADDRESS(egl, PostSubBufferNV);
+
+ // EGL_EXT_platform_base
+ INSERT_PROC_ADDRESS(egl, GetPlatformDisplayEXT);
+
+ // EGL_EXT_device_query
+ INSERT_PROC_ADDRESS(egl, QueryDisplayAttribEXT);
+ INSERT_PROC_ADDRESS(egl, QueryDeviceAttribEXT);
+ INSERT_PROC_ADDRESS(egl, QueryDeviceStringEXT);
+
+ // EGL_KHR_image_base/EGL_KHR_image
+ INSERT_PROC_ADDRESS(egl, CreateImageKHR);
+ INSERT_PROC_ADDRESS(egl, DestroyImageKHR);
+
+ // EGL_EXT_device_creation
+ INSERT_PROC_ADDRESS(egl, CreateDeviceANGLE);
+ INSERT_PROC_ADDRESS(egl, ReleaseDeviceANGLE);
+
+#undef INSERT_PROC_ADDRESS
+ return map;
};
- static const Extension extensions[] =
- {
- { "eglQuerySurfacePointerANGLE", (__eglMustCastToProperFunctionPointerType)QuerySurfacePointerANGLE },
- { "eglPostSubBufferNV", (__eglMustCastToProperFunctionPointerType)PostSubBufferNV },
- { "eglGetPlatformDisplayEXT", (__eglMustCastToProperFunctionPointerType)GetPlatformDisplayEXT },
- { "glBlitFramebufferANGLE", (__eglMustCastToProperFunctionPointerType)gl::BlitFramebufferANGLE },
- { "glRenderbufferStorageMultisampleANGLE", (__eglMustCastToProperFunctionPointerType)gl::RenderbufferStorageMultisampleANGLE },
- { "glDeleteFencesNV", (__eglMustCastToProperFunctionPointerType)gl::DeleteFencesNV },
- { "glGenFencesNV", (__eglMustCastToProperFunctionPointerType)gl::GenFencesNV },
- { "glIsFenceNV", (__eglMustCastToProperFunctionPointerType)gl::IsFenceNV },
- { "glTestFenceNV", (__eglMustCastToProperFunctionPointerType)gl::TestFenceNV },
- { "glGetFenceivNV", (__eglMustCastToProperFunctionPointerType)gl::GetFenceivNV },
- { "glFinishFenceNV", (__eglMustCastToProperFunctionPointerType)gl::FinishFenceNV },
- { "glSetFenceNV", (__eglMustCastToProperFunctionPointerType)gl::SetFenceNV },
- { "glGetTranslatedShaderSourceANGLE", (__eglMustCastToProperFunctionPointerType)gl::GetTranslatedShaderSourceANGLE },
- { "glTexStorage2DEXT", (__eglMustCastToProperFunctionPointerType)gl::TexStorage2DEXT },
- { "glGetGraphicsResetStatusEXT", (__eglMustCastToProperFunctionPointerType)gl::GetGraphicsResetStatusEXT },
- { "glReadnPixelsEXT", (__eglMustCastToProperFunctionPointerType)gl::ReadnPixelsEXT },
- { "glGetnUniformfvEXT", (__eglMustCastToProperFunctionPointerType)gl::GetnUniformfvEXT },
- { "glGetnUniformivEXT", (__eglMustCastToProperFunctionPointerType)gl::GetnUniformivEXT },
- { "glGenQueriesEXT", (__eglMustCastToProperFunctionPointerType)gl::GenQueriesEXT },
- { "glDeleteQueriesEXT", (__eglMustCastToProperFunctionPointerType)gl::DeleteQueriesEXT },
- { "glIsQueryEXT", (__eglMustCastToProperFunctionPointerType)gl::IsQueryEXT },
- { "glBeginQueryEXT", (__eglMustCastToProperFunctionPointerType)gl::BeginQueryEXT },
- { "glEndQueryEXT", (__eglMustCastToProperFunctionPointerType)gl::EndQueryEXT },
- { "glGetQueryivEXT", (__eglMustCastToProperFunctionPointerType)gl::GetQueryivEXT },
- { "glGetQueryObjectuivEXT", (__eglMustCastToProperFunctionPointerType)gl::GetQueryObjectuivEXT },
- { "glDrawBuffersEXT", (__eglMustCastToProperFunctionPointerType)gl::DrawBuffersEXT },
- { "glVertexAttribDivisorANGLE", (__eglMustCastToProperFunctionPointerType)gl::VertexAttribDivisorANGLE },
- { "glDrawArraysInstancedANGLE", (__eglMustCastToProperFunctionPointerType)gl::DrawArraysInstancedANGLE },
- { "glDrawElementsInstancedANGLE", (__eglMustCastToProperFunctionPointerType)gl::DrawElementsInstancedANGLE },
- { "glGetProgramBinaryOES", (__eglMustCastToProperFunctionPointerType)gl::GetProgramBinaryOES },
- { "glProgramBinaryOES", (__eglMustCastToProperFunctionPointerType)gl::ProgramBinaryOES },
- { "glGetBufferPointervOES", (__eglMustCastToProperFunctionPointerType)gl::GetBufferPointervOES },
- { "glMapBufferOES", (__eglMustCastToProperFunctionPointerType)gl::MapBufferOES },
- { "glUnmapBufferOES", (__eglMustCastToProperFunctionPointerType)gl::UnmapBufferOES },
- { "glMapBufferRangeEXT", (__eglMustCastToProperFunctionPointerType)gl::MapBufferRangeEXT },
- { "glFlushMappedBufferRangeEXT", (__eglMustCastToProperFunctionPointerType)gl::FlushMappedBufferRangeEXT },
- { "", NULL },
- };
+ static const ProcAddressMap procAddressMap = generateProcAddressMap();
- for (const Extension *extension = &extensions[0]; extension->address != nullptr; extension++)
+ auto iter = procAddressMap.find(procname);
+ if (iter != procAddressMap.end())
{
- if (strcmp(procname, extension->name) == 0)
- {
- return reinterpret_cast<__eglMustCastToProperFunctionPointerType>(extension->address);
- }
+ return iter->second;
+ }
+ else
+ {
+ return nullptr;
}
-
- return NULL;
}
}
diff --git a/src/3rdparty/angle/src/libGLESv2/entry_points_egl_ext.cpp b/src/3rdparty/angle/src/libGLESv2/entry_points_egl_ext.cpp
index 02b663192d..6c7e2ffc3d 100644
--- a/src/3rdparty/angle/src/libGLESv2/entry_points_egl_ext.cpp
+++ b/src/3rdparty/angle/src/libGLESv2/entry_points_egl_ext.cpp
@@ -10,6 +10,7 @@
#include "libGLESv2/global_state.h"
#include "libANGLE/Display.h"
+#include "libANGLE/Device.h"
#include "libANGLE/Surface.h"
#include "libANGLE/validationEGL.h"
@@ -58,7 +59,13 @@ EGLBoolean EGLAPIENTRY QuerySurfacePointerANGLE(EGLDisplay dpy, EGLSurface surfa
return EGL_FALSE;
}
break;
-
+ case EGL_DXGI_KEYED_MUTEX_ANGLE:
+ if (!display->getExtensions().keyedMutex)
+ {
+ SetGlobalError(Error(EGL_BAD_ATTRIBUTE));
+ return EGL_FALSE;
+ }
+ break;
default:
SetGlobalError(Error(EGL_BAD_ATTRIBUTE));
return EGL_FALSE;
@@ -140,136 +147,412 @@ EGLDisplay EGLAPIENTRY GetPlatformDisplayEXT(EGLenum platform, void *native_disp
return EGL_NO_DISPLAY;
}
break;
-
+ case EGL_PLATFORM_DEVICE_EXT:
+ if (!clientExtensions.platformDevice)
+ {
+ SetGlobalError(Error(EGL_BAD_PARAMETER, "Platform Device extension is not active"));
+ return EGL_NO_DISPLAY;
+ }
+ break;
default:
SetGlobalError(Error(EGL_BAD_CONFIG));
return EGL_NO_DISPLAY;
}
- EGLint platformType = EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE;
- EGLint deviceType = EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE;
- bool majorVersionSpecified = false;
- bool minorVersionSpecified = false;
- bool enableAutoTrimSpecified = false;
-
- if (attrib_list)
+ if (platform == EGL_PLATFORM_ANGLE_ANGLE)
{
- for (const EGLint *curAttrib = attrib_list; curAttrib[0] != EGL_NONE; curAttrib += 2)
+ EGLint platformType = EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE;
+ EGLint deviceType = EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE;
+ bool majorVersionSpecified = false;
+ bool minorVersionSpecified = false;
+ bool enableAutoTrimSpecified = false;
+ bool deviceTypeSpecified = false;
+ bool presentPathSpecified = false;
+
+ if (attrib_list)
{
- switch (curAttrib[0])
+ for (const EGLint *curAttrib = attrib_list; curAttrib[0] != EGL_NONE; curAttrib += 2)
{
- case EGL_PLATFORM_ANGLE_TYPE_ANGLE:
- switch (curAttrib[1])
+ switch (curAttrib[0])
{
- case EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE:
- break;
-
- case EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE:
- case EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE:
- if (!clientExtensions.platformANGLED3D)
+ case EGL_PLATFORM_ANGLE_TYPE_ANGLE:
+ switch (curAttrib[1])
{
+ case EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE:
+ break;
+
+ case EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE:
+ case EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE:
+ if (!clientExtensions.platformANGLED3D)
+ {
+ SetGlobalError(Error(EGL_BAD_ATTRIBUTE));
+ return EGL_NO_DISPLAY;
+ }
+ break;
+
+ case EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE:
+ case EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE:
+ if (!clientExtensions.platformANGLEOpenGL)
+ {
+ SetGlobalError(Error(EGL_BAD_ATTRIBUTE));
+ return EGL_NO_DISPLAY;
+ }
+ break;
+
+ default:
SetGlobalError(Error(EGL_BAD_ATTRIBUTE));
return EGL_NO_DISPLAY;
}
+ platformType = curAttrib[1];
break;
- case EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE:
- case EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE:
- if (!clientExtensions.platformANGLEOpenGL)
+ case EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE:
+ if (curAttrib[1] != EGL_DONT_CARE)
+ {
+ majorVersionSpecified = true;
+ }
+ break;
+
+ case EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE:
+ if (curAttrib[1] != EGL_DONT_CARE)
+ {
+ minorVersionSpecified = true;
+ }
+ break;
+
+ case EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE:
+ switch (curAttrib[1])
{
+ case EGL_TRUE:
+ case EGL_FALSE:
+ break;
+ default:
SetGlobalError(Error(EGL_BAD_ATTRIBUTE));
return EGL_NO_DISPLAY;
}
+ enableAutoTrimSpecified = true;
break;
- default:
- SetGlobalError(Error(EGL_BAD_ATTRIBUTE));
- return EGL_NO_DISPLAY;
- }
- platformType = curAttrib[1];
- break;
+ case EGL_EXPERIMENTAL_PRESENT_PATH_ANGLE:
+ if (!clientExtensions.experimentalPresentPath)
+ {
+ SetGlobalError(
+ Error(EGL_BAD_ATTRIBUTE,
+ "EGL_ANGLE_experimental_present_path extension not active"));
+ return EGL_NO_DISPLAY;
+ }
+
+ switch (curAttrib[1])
+ {
+ case EGL_EXPERIMENTAL_PRESENT_PATH_FAST_ANGLE:
+ case EGL_EXPERIMENTAL_PRESENT_PATH_COPY_ANGLE:
+ break;
+ default:
+ SetGlobalError(
+ Error(EGL_BAD_ATTRIBUTE,
+ "Invalid value for EGL_EXPERIMENTAL_PRESENT_PATH_ANGLE"));
+ return EGL_NO_DISPLAY;
+ }
+ presentPathSpecified = true;
+ break;
+
+ case EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE:
+ switch (curAttrib[1])
+ {
+ case EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE:
+ case EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE:
+ case EGL_PLATFORM_ANGLE_DEVICE_TYPE_REFERENCE_ANGLE:
+ deviceTypeSpecified = true;
+ break;
+
+ case EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE:
+ // This is a hidden option, accepted by the OpenGL back-end.
+ break;
+
+ default:
+ SetGlobalError(Error(EGL_BAD_ATTRIBUTE,
+ "Invalid value for "
+ "EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE "
+ "attrib"));
+ return EGL_NO_DISPLAY;
+ }
+ deviceType = curAttrib[1];
+ break;
- case EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE:
- if (curAttrib[1] != EGL_DONT_CARE)
- {
- majorVersionSpecified = true;
+ default:
+ break;
}
- break;
+ }
+ }
- case EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE:
- if (curAttrib[1] != EGL_DONT_CARE)
- {
- minorVersionSpecified = true;
- }
- break;
+ if (!majorVersionSpecified && minorVersionSpecified)
+ {
+ SetGlobalError(Error(EGL_BAD_ATTRIBUTE));
+ return EGL_NO_DISPLAY;
+ }
- case EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE:
- switch (curAttrib[1])
- {
- case EGL_TRUE:
- case EGL_FALSE:
- break;
- default:
- SetGlobalError(Error(EGL_BAD_ATTRIBUTE));
- return EGL_NO_DISPLAY;
- }
- enableAutoTrimSpecified = true;
- break;
+ if (deviceType == EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE &&
+ platformType != EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE)
+ {
+ SetGlobalError(
+ Error(EGL_BAD_ATTRIBUTE,
+ "EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE requires a device type of "
+ "EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE."));
+ return EGL_NO_DISPLAY;
+ }
- case EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE:
- if (!clientExtensions.platformANGLED3D)
- {
- SetGlobalError(Error(EGL_BAD_ATTRIBUTE));
- return EGL_NO_DISPLAY;
- }
+ if (enableAutoTrimSpecified && platformType != EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE)
+ {
+ SetGlobalError(
+ Error(EGL_BAD_ATTRIBUTE,
+ "EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE requires a device type of "
+ "EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE."));
+ return EGL_NO_DISPLAY;
+ }
- switch (curAttrib[1])
- {
- case EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE:
- case EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE:
- case EGL_PLATFORM_ANGLE_DEVICE_TYPE_REFERENCE_ANGLE:
- case EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE:
- break;
+ if (presentPathSpecified && platformType != EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE)
+ {
+ SetGlobalError(Error(EGL_BAD_ATTRIBUTE,
+ "EGL_EXPERIMENTAL_PRESENT_PATH_ANGLE requires a device type of "
+ "EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE."));
+ return EGL_NO_DISPLAY;
+ }
- default:
- SetGlobalError(Error(EGL_BAD_ATTRIBUTE));
- return EGL_NO_DISPLAY;
- }
- deviceType = curAttrib[1];
- break;
+ if (deviceTypeSpecified && platformType != EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE &&
+ platformType != EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE)
+ {
+ SetGlobalError(
+ Error(EGL_BAD_ATTRIBUTE,
+ "EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE requires a device type of "
+ "EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE or EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE."));
+ return EGL_NO_DISPLAY;
+ }
- default:
- break;
- }
+ SetGlobalError(Error(EGL_SUCCESS));
+ return Display::GetDisplayFromAttribs(native_display, AttributeMap(attrib_list));
+ }
+ else if (platform == EGL_PLATFORM_DEVICE_EXT)
+ {
+ Device *eglDevice = reinterpret_cast<Device *>(native_display);
+ if (eglDevice == nullptr || !Device::IsValidDevice(eglDevice))
+ {
+ SetGlobalError(Error(EGL_BAD_ATTRIBUTE,
+ "native_display should be a valid EGL device if platform equals "
+ "EGL_PLATFORM_DEVICE_EXT"));
+ return EGL_NO_DISPLAY;
}
+
+ SetGlobalError(Error(EGL_SUCCESS));
+ return Display::GetDisplayFromDevice(native_display);
+ }
+ else
+ {
+ UNREACHABLE();
+ return EGL_NO_DISPLAY;
+ }
+}
+
+// EGL_EXT_device_query
+EGLBoolean EGLAPIENTRY QueryDeviceAttribEXT(EGLDeviceEXT device, EGLint attribute, EGLAttrib *value)
+{
+ EVENT("(EGLDeviceEXT device = 0x%0.8p, EGLint attribute = %d, EGLAttrib *value = 0x%0.8p)",
+ device, attribute, value);
+
+ Device *dev = static_cast<Device*>(device);
+ if (dev == EGL_NO_DEVICE_EXT || !Device::IsValidDevice(dev))
+ {
+ SetGlobalError(Error(EGL_BAD_ACCESS));
+ return EGL_FALSE;
+ }
+
+ // If the device was created by (and is owned by) a display, and that display doesn't support
+ // device querying, then this call should fail
+ Display *owningDisplay = dev->getOwningDisplay();
+ if (owningDisplay != nullptr && !owningDisplay->getExtensions().deviceQuery)
+ {
+ SetGlobalError(Error(EGL_BAD_ACCESS,
+ "Device wasn't created using eglCreateDeviceANGLE, and the Display "
+ "that created it doesn't support device querying"));
+ return EGL_FALSE;
}
- if (!majorVersionSpecified && minorVersionSpecified)
+ Error error(EGL_SUCCESS);
+
+ // validate the attribute parameter
+ switch (attribute)
{
+ case EGL_D3D11_DEVICE_ANGLE:
+ case EGL_D3D9_DEVICE_ANGLE:
+ if (!dev->getExtensions().deviceD3D || dev->getType() != attribute)
+ {
+ SetGlobalError(Error(EGL_BAD_ATTRIBUTE));
+ return EGL_FALSE;
+ }
+ error = dev->getDevice(value);
+ break;
+ default:
SetGlobalError(Error(EGL_BAD_ATTRIBUTE));
- return EGL_NO_DISPLAY;
+ return EGL_FALSE;
}
- if (deviceType == EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE &&
- platformType != EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE)
+ SetGlobalError(error);
+ return (error.isError() ? EGL_FALSE : EGL_TRUE);
+}
+
+// EGL_EXT_device_query
+const char * EGLAPIENTRY QueryDeviceStringEXT(EGLDeviceEXT device, EGLint name)
+{
+ EVENT("(EGLDeviceEXT device = 0x%0.8p, EGLint name = %d)",
+ device, name);
+
+ Device *dev = static_cast<Device*>(device);
+ if (dev == EGL_NO_DEVICE_EXT || !Device::IsValidDevice(dev))
{
- SetGlobalError(Error(EGL_BAD_ATTRIBUTE, "EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE requires a device type of "
- "EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE."));
- return EGL_NO_DISPLAY;
+ SetGlobalError(Error(EGL_BAD_DEVICE_EXT));
+ return nullptr;
}
- if (enableAutoTrimSpecified &&
- platformType != EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE)
+ const char *result;
+ switch (name)
{
- SetGlobalError(Error(EGL_BAD_ATTRIBUTE, "EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE requires a device type of "
- "EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE."));
- return EGL_NO_DISPLAY;
+ case EGL_EXTENSIONS:
+ result = dev->getExtensionString().c_str();
+ break;
+ default:
+ SetGlobalError(Error(EGL_BAD_DEVICE_EXT));
+ return nullptr;
}
SetGlobalError(Error(EGL_SUCCESS));
+ return result;
+}
+
+// EGL_EXT_device_query
+EGLBoolean EGLAPIENTRY QueryDisplayAttribEXT(EGLDisplay dpy, EGLint attribute, EGLAttrib *value)
+{
+ EVENT("(EGLDisplay dpy = 0x%0.8p, EGLint attribute = %d, EGLAttrib *value = 0x%0.8p)",
+ dpy, attribute, value);
+
+ Display *display = static_cast<Display*>(dpy);
+ Error error(EGL_SUCCESS);
+
+ if (!display->getExtensions().deviceQuery)
+ {
+ SetGlobalError(Error(EGL_BAD_ACCESS));
+ return EGL_FALSE;
+ }
+
+ // validate the attribute parameter
+ switch (attribute)
+ {
+ case EGL_DEVICE_EXT:
+ *value = reinterpret_cast<EGLAttrib>(display->getDevice());
+ break;
+
+ default:
+ SetGlobalError(Error(EGL_BAD_ATTRIBUTE));
+ return EGL_FALSE;
+ }
+
+ SetGlobalError(error);
+ return (error.isError() ? EGL_FALSE : EGL_TRUE);
+}
+
+ANGLE_EXPORT EGLImageKHR EGLAPIENTRY CreateImageKHR(EGLDisplay dpy,
+ EGLContext ctx,
+ EGLenum target,
+ EGLClientBuffer buffer,
+ const EGLint *attrib_list)
+{
+ EVENT(
+ "(EGLDisplay dpy = 0x%0.8p, EGLContext ctx = 0x%0.8p, EGLenum target = 0x%X, "
+ "EGLClientBuffer buffer = 0x%0.8p, const EGLAttrib *attrib_list = 0x%0.8p)",
+ dpy, ctx, target, buffer, attrib_list);
+
+ Display *display = static_cast<Display *>(dpy);
+ gl::Context *context = static_cast<gl::Context *>(ctx);
+ AttributeMap attributes(attrib_list);
+
+ Error error = ValidateCreateImageKHR(display, context, target, buffer, attributes);
+ if (error.isError())
+ {
+ SetGlobalError(error);
+ return EGL_NO_IMAGE;
+ }
+
+ Image *image = nullptr;
+ error = display->createImage(context, target, buffer, attributes, &image);
+ if (error.isError())
+ {
+ SetGlobalError(error);
+ return EGL_NO_IMAGE;
+ }
+
+ return static_cast<EGLImage>(image);
+}
+
+ANGLE_EXPORT EGLBoolean EGLAPIENTRY DestroyImageKHR(EGLDisplay dpy, EGLImageKHR image)
+{
+ EVENT("(EGLDisplay dpy = 0x%0.8p, EGLImage image = 0x%0.8p)", dpy, image);
+
+ Display *display = static_cast<Display *>(dpy);
+ Image *img = static_cast<Image *>(image);
+
+ Error error = ValidateDestroyImageKHR(display, img);
+ if (error.isError())
+ {
+ SetGlobalError(error);
+ return EGL_FALSE;
+ }
+
+ display->destroyImage(img);
+
+ return EGL_TRUE;
+}
+
+ANGLE_EXPORT EGLDeviceEXT EGLAPIENTRY CreateDeviceANGLE(EGLint device_type,
+ void *native_device,
+ const EGLAttrib *attrib_list)
+{
+ EVENT(
+ "(EGLint device_type = %d, void* native_device = 0x%0.8p, const EGLAttrib* attrib_list = "
+ "0x%0.8p)",
+ device_type, native_device, attrib_list);
+
+ Error error = ValidateCreateDeviceANGLE(device_type, native_device, attrib_list);
+ if (error.isError())
+ {
+ SetGlobalError(error);
+ return EGL_NO_DEVICE_EXT;
+ }
+
+ Device *device = nullptr;
+ error = Device::CreateDevice(native_device, device_type, &device);
+ if (error.isError())
+ {
+ ASSERT(device == nullptr);
+ SetGlobalError(error);
+ return EGL_NO_DEVICE_EXT;
+ }
- EGLNativeDisplayType displayId = static_cast<EGLNativeDisplayType>(native_display);
- return Display::getDisplay(displayId, AttributeMap(attrib_list));
+ return device;
}
+ANGLE_EXPORT EGLBoolean EGLAPIENTRY ReleaseDeviceANGLE(EGLDeviceEXT device)
+{
+ EVENT("(EGLDeviceEXT device = 0x%0.8p)", device);
+
+ Device *dev = static_cast<Device *>(device);
+
+ Error error = ValidateReleaseDeviceANGLE(dev);
+ if (error.isError())
+ {
+ SetGlobalError(error);
+ return EGL_FALSE;
+ }
+
+ SafeDelete(dev);
+
+ return EGL_TRUE;
+}
}
diff --git a/src/3rdparty/angle/src/libGLESv2/entry_points_egl_ext.h b/src/3rdparty/angle/src/libGLESv2/entry_points_egl_ext.h
index 9de1027082..d64fa6e483 100644
--- a/src/3rdparty/angle/src/libGLESv2/entry_points_egl_ext.h
+++ b/src/3rdparty/angle/src/libGLESv2/entry_points_egl_ext.h
@@ -25,6 +25,24 @@ ANGLE_EXPORT EGLBoolean EGLAPIENTRY PostSubBufferNV(EGLDisplay dpy, EGLSurface s
// EGL_EXT_platform_base
ANGLE_EXPORT EGLDisplay EGLAPIENTRY GetPlatformDisplayEXT(EGLenum platform, void *native_display, const EGLint *attrib_list);
+// EGL_EXT_device_query
+ANGLE_EXPORT EGLBoolean EGLAPIENTRY QueryDisplayAttribEXT(EGLDisplay dpy, EGLint attribute, EGLAttrib *value);
+ANGLE_EXPORT EGLBoolean EGLAPIENTRY QueryDeviceAttribEXT(EGLDeviceEXT device, EGLint attribute, EGLAttrib *value);
+ANGLE_EXPORT const char * EGLAPIENTRY QueryDeviceStringEXT(EGLDeviceEXT device, EGLint name);
+
+// EGL_KHR_image_base/EGL_KHR_image
+ANGLE_EXPORT EGLImageKHR EGLAPIENTRY CreateImageKHR(EGLDisplay dpy,
+ EGLContext ctx,
+ EGLenum target,
+ EGLClientBuffer buffer,
+ const EGLint *attrib_list);
+ANGLE_EXPORT EGLBoolean EGLAPIENTRY DestroyImageKHR(EGLDisplay dpy, EGLImageKHR image);
+
+// EGL_EXT_device_creation
+ANGLE_EXPORT EGLDeviceEXT EGLAPIENTRY CreateDeviceANGLE(EGLint device_type,
+ void *native_device,
+ const EGLAttrib *attrib_list);
+ANGLE_EXPORT EGLBoolean EGLAPIENTRY ReleaseDeviceANGLE(EGLDeviceEXT device);
}
#endif // LIBGLESV2_ENTRYPOINTSEGLEXT_H_
diff --git a/src/3rdparty/angle/src/libGLESv2/entry_points_gles_2_0.cpp b/src/3rdparty/angle/src/libGLESv2/entry_points_gles_2_0.cpp
index 6d3089ba4f..336b320ba5 100644
--- a/src/3rdparty/angle/src/libGLESv2/entry_points_gles_2_0.cpp
+++ b/src/3rdparty/angle/src/libGLESv2/entry_points_gles_2_0.cpp
@@ -59,35 +59,16 @@ void GL_APIENTRY AttachShader(GLuint program, GLuint shader)
Context *context = GetValidGlobalContext();
if (context)
{
- Program *programObject = context->getProgram(program);
- Shader *shaderObject = context->getShader(shader);
-
+ Program *programObject = GetValidProgram(context, program);
if (!programObject)
{
- if (context->getShader(program))
- {
- context->recordError(Error(GL_INVALID_OPERATION));
- return;
- }
- else
- {
- context->recordError(Error(GL_INVALID_VALUE));
- return;
- }
+ return;
}
+ Shader *shaderObject = GetValidShader(context, shader);
if (!shaderObject)
{
- if (context->getProgram(shader))
- {
- context->recordError(Error(GL_INVALID_OPERATION));
- return;
- }
- else
- {
- context->recordError(Error(GL_INVALID_VALUE));
- return;
- }
+ return;
}
if (!programObject->attachShader(shaderObject))
@@ -111,20 +92,11 @@ void GL_APIENTRY BindAttribLocation(GLuint program, GLuint index, const GLchar*
return;
}
- Program *programObject = context->getProgram(program);
+ Program *programObject = GetValidProgram(context, program);
if (!programObject)
{
- if (context->getShader(program))
- {
- context->recordError(Error(GL_INVALID_OPERATION));
- return;
- }
- else
- {
- context->recordError(Error(GL_INVALID_VALUE));
- return;
- }
+ return;
}
if (strncmp(name, "gl_", 3) == 0)
@@ -444,17 +416,25 @@ void GL_APIENTRY BlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha
return;
}
- bool constantColorUsed = (srcRGB == GL_CONSTANT_COLOR || srcRGB == GL_ONE_MINUS_CONSTANT_COLOR ||
- dstRGB == GL_CONSTANT_COLOR || dstRGB == GL_ONE_MINUS_CONSTANT_COLOR);
+ if (context->getLimitations().noSimultaneousConstantColorAndAlphaBlendFunc)
+ {
+ bool constantColorUsed =
+ (srcRGB == GL_CONSTANT_COLOR || srcRGB == GL_ONE_MINUS_CONSTANT_COLOR ||
+ dstRGB == GL_CONSTANT_COLOR || dstRGB == GL_ONE_MINUS_CONSTANT_COLOR);
- bool constantAlphaUsed = (srcRGB == GL_CONSTANT_ALPHA || srcRGB == GL_ONE_MINUS_CONSTANT_ALPHA ||
- dstRGB == GL_CONSTANT_ALPHA || dstRGB == GL_ONE_MINUS_CONSTANT_ALPHA);
+ bool constantAlphaUsed =
+ (srcRGB == GL_CONSTANT_ALPHA || srcRGB == GL_ONE_MINUS_CONSTANT_ALPHA ||
+ dstRGB == GL_CONSTANT_ALPHA || dstRGB == GL_ONE_MINUS_CONSTANT_ALPHA);
- if (constantColorUsed && constantAlphaUsed)
- {
- ERR("Simultaneous use of GL_CONSTANT_ALPHA/GL_ONE_MINUS_CONSTANT_ALPHA and GL_CONSTANT_COLOR/GL_ONE_MINUS_CONSTANT_COLOR invalid under WebGL");
- context->recordError(Error(GL_INVALID_OPERATION));
- return;
+ if (constantColorUsed && constantAlphaUsed)
+ {
+ ERR(
+ "Simultaneous use of GL_CONSTANT_ALPHA/GL_ONE_MINUS_CONSTANT_ALPHA and "
+ "GL_CONSTANT_COLOR/GL_ONE_MINUS_CONSTANT_COLOR not supported by this "
+ "implementation.");
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return;
+ }
}
context->getState().setBlendFactors(srcRGB, dstRGB, srcAlpha, dstAlpha);
@@ -537,11 +517,6 @@ void GL_APIENTRY BufferSubData(GLenum target, GLintptr offset, GLsizeiptr size,
return;
}
- if (data == NULL)
- {
- return;
- }
-
if (!ValidBufferTarget(context, target))
{
context->recordError(Error(GL_INVALID_ENUM));
@@ -575,6 +550,11 @@ void GL_APIENTRY BufferSubData(GLenum target, GLintptr offset, GLsizeiptr size,
return;
}
+ if (data == NULL)
+ {
+ return;
+ }
+
Error error = buffer->bufferSubData(data, size, offset);
if (error.isError())
{
@@ -613,27 +593,12 @@ void GL_APIENTRY Clear(GLbitfield mask)
Context *context = GetValidGlobalContext();
if (context)
{
- Framebuffer *framebufferObject = context->getState().getDrawFramebuffer();
- ASSERT(framebufferObject);
-
- if (framebufferObject->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
- {
- context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
- return;
- }
-
- if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) != 0)
+ if (!context->skipValidation() && !ValidateClear(context, mask))
{
- context->recordError(Error(GL_INVALID_VALUE));
return;
}
- Error error = framebufferObject->clear(context->getData(), mask);
- if (error.isError())
- {
- context->recordError(error);
- return;
- }
+ context->clear(mask);
}
}
@@ -690,22 +655,11 @@ void GL_APIENTRY CompileShader(GLuint shader)
Context *context = GetValidGlobalContext();
if (context)
{
- Shader *shaderObject = context->getShader(shader);
-
+ Shader *shaderObject = GetValidShader(context, shader);
if (!shaderObject)
{
- if (context->getProgram(shader))
- {
- context->recordError(Error(GL_INVALID_OPERATION));
- return;
- }
- else
- {
- context->recordError(Error(GL_INVALID_VALUE));
- return;
- }
+ return;
}
-
shaderObject->compile(context->getCompiler());
}
}
@@ -728,8 +682,9 @@ void GL_APIENTRY CompressedTexImage2D(GLenum target, GLint level, GLenum interna
}
if (context->getClientVersion() >= 3 &&
- !ValidateES3TexImageParameters(context, target, level, internalformat, true, false,
- 0, 0, 0, width, height, 1, border, GL_NONE, GL_NONE, data))
+ !ValidateES3TexImage2DParameters(context, target, level, internalformat, true, false, 0,
+ 0, 0, width, height, 1, border, GL_NONE, GL_NONE,
+ data))
{
return;
}
@@ -743,8 +698,9 @@ void GL_APIENTRY CompressedTexImage2D(GLenum target, GLint level, GLenum interna
Extents size(width, height, 1);
Texture *texture = context->getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target);
- Error error = texture->setCompressedImage(target, level, internalformat, size, context->getState().getUnpackState(),
- reinterpret_cast<const uint8_t *>(data));
+ Error error =
+ texture->setCompressedImage(context, target, level, internalformat, size, imageSize,
+ reinterpret_cast<const uint8_t *>(data));
if (error.isError())
{
context->recordError(error);
@@ -772,8 +728,9 @@ void GL_APIENTRY CompressedTexSubImage2D(GLenum target, GLint level, GLint xoffs
}
if (context->getClientVersion() >= 3 &&
- !ValidateES3TexImageParameters(context, target, level, GL_NONE, true, true,
- xoffset, yoffset, 0, width, height, 1, 0, GL_NONE, GL_NONE, data))
+ !ValidateES3TexImage2DParameters(context, target, level, GL_NONE, true, true, xoffset,
+ yoffset, 0, width, height, 1, 0, GL_NONE, GL_NONE,
+ data))
{
return;
}
@@ -785,11 +742,11 @@ void GL_APIENTRY CompressedTexSubImage2D(GLenum target, GLint level, GLint xoffs
return;
}
-
Box area(xoffset, yoffset, 0, width, height, 1);
Texture *texture = context->getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target);
- Error error = texture->setCompressedSubImage(target, level, area, format, context->getState().getUnpackState(),
- reinterpret_cast<const uint8_t *>(data));
+ Error error =
+ texture->setCompressedSubImage(context, target, level, area, format, imageSize,
+ reinterpret_cast<const uint8_t *>(data));
if (error.isError())
{
context->recordError(error);
@@ -807,30 +764,13 @@ void GL_APIENTRY CopyTexImage2D(GLenum target, GLint level, GLenum internalforma
Context *context = GetValidGlobalContext();
if (context)
{
- if (context->getClientVersion() < 3 &&
- !ValidateES2CopyTexImageParameters(context, target, level, internalformat, false,
- 0, 0, x, y, width, height, border))
- {
- return;
- }
-
- if (context->getClientVersion() >= 3 &&
- !ValidateES3CopyTexImageParameters(context, target, level, internalformat, false,
- 0, 0, 0, x, y, width, height, border))
- {
- return;
- }
-
- Rectangle sourceArea(x, y, width, height);
-
- const Framebuffer *framebuffer = context->getState().getReadFramebuffer();
- Texture *texture = context->getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target);
- Error error = texture->copyImage(target, level, sourceArea, internalformat, framebuffer);
- if (error.isError())
+ if (!context->skipValidation() &&
+ !ValidateCopyTexImage2D(context, target, level, internalformat, x, y, width, height,
+ border))
{
- context->recordError(error);
return;
}
+ context->copyTexImage2D(target, level, internalformat, x, y, width, height, border);
}
}
@@ -843,31 +783,14 @@ void GL_APIENTRY CopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GL
Context *context = GetValidGlobalContext();
if (context)
{
- if (context->getClientVersion() < 3 &&
- !ValidateES2CopyTexImageParameters(context, target, level, GL_NONE, true,
- xoffset, yoffset, x, y, width, height, 0))
- {
- return;
- }
-
- if (context->getClientVersion() >= 3 &&
- !ValidateES3CopyTexImageParameters(context, target, level, GL_NONE, true,
- xoffset, yoffset, 0, x, y, width, height, 0))
+ if (!context->skipValidation() &&
+ !ValidateCopyTexSubImage2D(context, target, level, xoffset, yoffset, x, y, width,
+ height))
{
return;
}
- Offset destOffset(xoffset, yoffset, 0);
- Rectangle sourceArea(x, y, width, height);
-
- const Framebuffer *framebuffer = context->getState().getReadFramebuffer();
- Texture *texture = context->getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target);
- Error error = texture->copySubImage(target, level, destOffset, sourceArea, framebuffer);
- if (error.isError())
- {
- context->recordError(error);
- return;
- }
+ context->copyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
}
}
@@ -1131,38 +1054,16 @@ void GL_APIENTRY DetachShader(GLuint program, GLuint shader)
Context *context = GetValidGlobalContext();
if (context)
{
- Program *programObject = context->getProgram(program);
- Shader *shaderObject = context->getShader(shader);
-
+ Program *programObject = GetValidProgram(context, program);
if (!programObject)
{
- Shader *shaderByProgramHandle;
- shaderByProgramHandle = context->getShader(program);
- if (!shaderByProgramHandle)
- {
- context->recordError(Error(GL_INVALID_VALUE));
- return;
- }
- else
- {
- context->recordError(Error(GL_INVALID_OPERATION));
- return;
- }
+ return;
}
+ Shader *shaderObject = GetValidShader(context, shader);
if (!shaderObject)
{
- Program *programByShaderHandle = context->getProgram(shader);
- if (!programByShaderHandle)
- {
- context->recordError(Error(GL_INVALID_VALUE));
- return;
- }
- else
- {
- context->recordError(Error(GL_INVALID_OPERATION));
- return;
- }
+ return;
}
if (!programObject->detachShader(shaderObject))
@@ -1219,7 +1120,7 @@ void GL_APIENTRY DrawArrays(GLenum mode, GLint first, GLsizei count)
return;
}
- Error error = context->drawArrays(mode, first, count, 0);
+ Error error = context->drawArrays(mode, first, count);
if (error.isError())
{
context->recordError(error);
@@ -1236,13 +1137,13 @@ void GL_APIENTRY DrawElements(GLenum mode, GLsizei count, GLenum type, const GLv
Context *context = GetValidGlobalContext();
if (context)
{
- rx::RangeUI indexRange;
+ IndexRange indexRange;
if (!ValidateDrawElements(context, mode, count, type, indices, 0, &indexRange))
{
return;
}
- Error error = context->drawElements(mode, count, type, indices, 0, indexRange);
+ Error error = context->drawElements(mode, count, type, indices, indexRange);
if (error.isError())
{
context->recordError(error);
@@ -1264,6 +1165,20 @@ void GL_APIENTRY Enable(GLenum cap)
return;
}
+ if (context->getLimitations().noSampleAlphaToCoverageSupport)
+ {
+ if (cap == GL_SAMPLE_ALPHA_TO_COVERAGE)
+ {
+ const char *errorMessage = "Current renderer doesn't support alpha-to-coverage";
+ context->recordError(Error(GL_INVALID_OPERATION, errorMessage));
+
+ // We also output an error message to the debugger window if tracing is active, so that developers can see the error message.
+ ERR("%s", errorMessage);
+
+ return;
+ }
+ }
+
context->getState().setEnableFeature(cap, true);
}
}
@@ -1325,29 +1240,14 @@ void GL_APIENTRY FramebufferRenderbuffer(GLenum target, GLenum attachment, GLenu
Context *context = GetValidGlobalContext();
if (context)
{
- if (!ValidFramebufferTarget(target) || (renderbuffertarget != GL_RENDERBUFFER && renderbuffer != 0))
- {
- context->recordError(Error(GL_INVALID_ENUM));
- return;
- }
-
- if (!ValidateFramebufferRenderbufferParameters(context, target, attachment, renderbuffertarget, renderbuffer))
+ if (!context->skipValidation() &&
+ !ValidateFramebufferRenderbuffer(context, target, attachment, renderbuffertarget,
+ renderbuffer))
{
return;
}
- Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
- ASSERT(framebuffer);
-
- if (renderbuffer != 0)
- {
- Renderbuffer *renderbufferObject = context->getRenderbuffer(renderbuffer);
- framebuffer->setRenderbufferAttachment(attachment, renderbufferObject);
- }
- else
- {
- framebuffer->setNULLAttachment(attachment);
- }
+ context->framebufferRenderbuffer(target, attachment, renderbuffertarget, renderbuffer);
}
}
@@ -1359,36 +1259,13 @@ void GL_APIENTRY FramebufferTexture2D(GLenum target, GLenum attachment, GLenum t
Context *context = GetValidGlobalContext();
if (context)
{
- if (!ValidateFramebufferTexture2D(context, target, attachment, textarget, texture, level))
+ if (!context->skipValidation() &&
+ !ValidateFramebufferTexture2D(context, target, attachment, textarget, texture, level))
{
return;
}
- Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
- ASSERT(framebuffer);
-
- if (texture != 0)
- {
- Texture *textureObj = context->getTexture(texture);
-
- ImageIndex index = ImageIndex::MakeInvalid();
-
- if (textarget == GL_TEXTURE_2D)
- {
- index = ImageIndex::Make2D(level);
- }
- else
- {
- ASSERT(IsCubeMapTextureTarget(textarget));
- index = ImageIndex::MakeCube(textarget, level);
- }
-
- framebuffer->setTextureAttachment(attachment, textureObj, index);
- }
- else
- {
- framebuffer->setNULLAttachment(attachment);
- }
+ context->framebufferTexture2D(target, attachment, textarget, texture, level);
}
}
@@ -1485,7 +1362,9 @@ void GL_APIENTRY GenerateMipmap(GLenum target)
}
// Non-power of 2 ES2 check
- if (!context->getExtensions().textureNPOT && (!isPow2(texture->getWidth(baseTarget, 0)) || !isPow2(texture->getHeight(baseTarget, 0))))
+ if (!context->getExtensions().textureNPOT &&
+ (!isPow2(static_cast<int>(texture->getWidth(baseTarget, 0))) ||
+ !isPow2(static_cast<int>(texture->getHeight(baseTarget, 0)))))
{
ASSERT(context->getClientVersion() <= 2 && (target == GL_TEXTURE_2D || target == GL_TEXTURE_CUBE_MAP));
context->recordError(Error(GL_INVALID_OPERATION));
@@ -1583,20 +1462,11 @@ void GL_APIENTRY GetActiveAttrib(GLuint program, GLuint index, GLsizei bufsize,
return;
}
- Program *programObject = context->getProgram(program);
+ Program *programObject = GetValidProgram(context, program);
if (!programObject)
{
- if (context->getShader(program))
- {
- context->recordError(Error(GL_INVALID_OPERATION));
- return;
- }
- else
- {
- context->recordError(Error(GL_INVALID_VALUE));
- return;
- }
+ return;
}
if (index >= (GLuint)programObject->getActiveAttributeCount())
@@ -1625,20 +1495,11 @@ void GL_APIENTRY GetActiveUniform(GLuint program, GLuint index, GLsizei bufsize,
return;
}
- Program *programObject = context->getProgram(program);
+ Program *programObject = GetValidProgram(context, program);
if (!programObject)
{
- if (context->getShader(program))
- {
- context->recordError(Error(GL_INVALID_OPERATION));
- return;
- }
- else
- {
- context->recordError(Error(GL_INVALID_VALUE));
- return;
- }
+ return;
}
if (index >= (GLuint)programObject->getActiveUniformCount())
@@ -1665,20 +1526,11 @@ void GL_APIENTRY GetAttachedShaders(GLuint program, GLsizei maxcount, GLsizei* c
return;
}
- Program *programObject = context->getProgram(program);
+ Program *programObject = GetValidProgram(context, program);
if (!programObject)
{
- if (context->getShader(program))
- {
- context->recordError(Error(GL_INVALID_OPERATION));
- return;
- }
- else
- {
- context->recordError(Error(GL_INVALID_VALUE));
- return;
- }
+ return;
}
return programObject->getAttachedShaders(maxcount, count, shaders);
@@ -1692,20 +1544,11 @@ GLint GL_APIENTRY GetAttribLocation(GLuint program, const GLchar* name)
Context *context = GetValidGlobalContext();
if (context)
{
- Program *programObject = context->getProgram(program);
+ Program *programObject = GetValidProgram(context, program);
if (!programObject)
{
- if (context->getShader(program))
- {
- context->recordError(Error(GL_INVALID_OPERATION));
- return -1;
- }
- else
- {
- context->recordError(Error(GL_INVALID_VALUE));
- return -1;
- }
+ return -1;
}
if (!programObject->isLinked())
@@ -1784,7 +1627,11 @@ void GL_APIENTRY GetBufferParameteriv(GLenum target, GLenum pname, GLint* params
case GL_BUFFER_ACCESS_FLAGS:
*params = buffer->getAccessFlags();
break;
+ case GL_BUFFER_ACCESS_OES:
+ *params = buffer->getAccess();
+ break;
case GL_BUFFER_MAPPED:
+ static_assert(GL_BUFFER_MAPPED == GL_BUFFER_MAPPED_OES, "GL enums should be equal.");
*params = static_cast<GLint>(buffer->isMapped());
break;
case GL_BUFFER_MAP_OFFSET:
@@ -1918,7 +1765,7 @@ void GL_APIENTRY GetFramebufferAttachmentParameteriv(GLenum target, GLenum attac
break;
}
- Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
+ const Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
ASSERT(framebuffer);
if (framebuffer->id() == 0)
@@ -2134,11 +1981,10 @@ void GL_APIENTRY GetProgramiv(GLuint program, GLenum pname, GLint* params)
Context *context = GetValidGlobalContext();
if (context)
{
- Program *programObject = context->getProgram(program);
+ Program *programObject = GetValidProgram(context, program);
if (!programObject)
{
- context->recordError(Error(GL_INVALID_VALUE));
return;
}
@@ -2151,6 +1997,7 @@ void GL_APIENTRY GetProgramiv(GLuint program, GLenum pname, GLint* params)
case GL_TRANSFORM_FEEDBACK_BUFFER_MODE:
case GL_TRANSFORM_FEEDBACK_VARYINGS:
case GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH:
+ case GL_PROGRAM_BINARY_RETRIEVABLE_HINT:
context->recordError(Error(GL_INVALID_ENUM));
return;
}
@@ -2203,6 +2050,9 @@ void GL_APIENTRY GetProgramiv(GLuint program, GLenum pname, GLint* params)
case GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH:
*params = programObject->getTransformFeedbackVaryingMaxLength();
break;
+ case GL_PROGRAM_BINARY_RETRIEVABLE_HINT:
+ *params = programObject->getBinaryRetrievableHint();
+ break;
default:
context->recordError(Error(GL_INVALID_ENUM));
@@ -2225,11 +2075,9 @@ void GL_APIENTRY GetProgramInfoLog(GLuint program, GLsizei bufsize, GLsizei* len
return;
}
- Program *programObject = context->getProgram(program);
-
+ Program *programObject = GetValidProgram(context, program);
if (!programObject)
{
- context->recordError(Error(GL_INVALID_VALUE));
return;
}
@@ -2293,11 +2141,9 @@ void GL_APIENTRY GetShaderiv(GLuint shader, GLenum pname, GLint* params)
Context *context = GetValidGlobalContext();
if (context)
{
- Shader *shaderObject = context->getShader(shader);
-
+ Shader *shaderObject = GetValidShader(context, shader);
if (!shaderObject)
{
- context->recordError(Error(GL_INVALID_VALUE));
return;
}
@@ -2319,7 +2165,7 @@ void GL_APIENTRY GetShaderiv(GLuint shader, GLenum pname, GLint* params)
*params = shaderObject->getSourceLength();
return;
case GL_TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE:
- *params = shaderObject->getTranslatedSourceLength();
+ *params = shaderObject->getTranslatedSourceWithDebugInfoLength();
return;
default:
@@ -2343,11 +2189,9 @@ void GL_APIENTRY GetShaderInfoLog(GLuint shader, GLsizei bufsize, GLsizei* lengt
return;
}
- Shader *shaderObject = context->getShader(shader);
-
+ Shader *shaderObject = GetValidShader(context, shader);
if (!shaderObject)
{
- context->recordError(Error(GL_INVALID_VALUE));
return;
}
@@ -2443,11 +2287,9 @@ void GL_APIENTRY GetShaderSource(GLuint shader, GLsizei bufsize, GLsizei* length
return;
}
- Shader *shaderObject = context->getShader(shader);
-
+ Shader *shaderObject = GetValidShader(context, shader);
if (!shaderObject)
{
- context->recordError(Error(GL_INVALID_OPERATION));
return;
}
@@ -2461,44 +2303,50 @@ const GLubyte *GL_APIENTRY GetString(GLenum name)
Context *context = GetValidGlobalContext();
- switch (name)
+ if (context)
{
- case GL_VENDOR:
- return (GLubyte*)"Google Inc.";
+ switch (name)
+ {
+ case GL_VENDOR:
+ return reinterpret_cast<const GLubyte *>("Google Inc.");
- case GL_RENDERER:
- return (GLubyte*)((context != NULL) ? context->getRendererString().c_str() : "ANGLE");
+ case GL_RENDERER:
+ return reinterpret_cast<const GLubyte *>(context->getRendererString().c_str());
- case GL_VERSION:
- if (context->getClientVersion() == 2)
- {
- return (GLubyte*)"OpenGL ES 2.0 (ANGLE " ANGLE_VERSION_STRING ")";
- }
- else
- {
- return (GLubyte*)"OpenGL ES 3.0 (ANGLE " ANGLE_VERSION_STRING ")";
- }
+ case GL_VERSION:
+ if (context->getClientVersion() == 2)
+ {
+ return reinterpret_cast<const GLubyte *>(
+ "OpenGL ES 2.0 (ANGLE " ANGLE_VERSION_STRING ")");
+ }
+ else
+ {
+ return reinterpret_cast<const GLubyte *>(
+ "OpenGL ES 3.0 (ANGLE " ANGLE_VERSION_STRING ")");
+ }
- case GL_SHADING_LANGUAGE_VERSION:
- if (context->getClientVersion() == 2)
- {
- return (GLubyte*)"OpenGL ES GLSL ES 1.00 (ANGLE " ANGLE_VERSION_STRING ")";
- }
- else
- {
- return (GLubyte*)"OpenGL ES GLSL ES 3.00 (ANGLE " ANGLE_VERSION_STRING ")";
- }
+ case GL_SHADING_LANGUAGE_VERSION:
+ if (context->getClientVersion() == 2)
+ {
+ return reinterpret_cast<const GLubyte *>(
+ "OpenGL ES GLSL ES 1.00 (ANGLE " ANGLE_VERSION_STRING ")");
+ }
+ else
+ {
+ return reinterpret_cast<const GLubyte *>(
+ "OpenGL ES GLSL ES 3.00 (ANGLE " ANGLE_VERSION_STRING ")");
+ }
- case GL_EXTENSIONS:
- return (GLubyte*)((context != NULL) ? context->getExtensionString().c_str() : "");
+ case GL_EXTENSIONS:
+ return reinterpret_cast<const GLubyte *>(context->getExtensionString().c_str());
- default:
- if (context)
- {
+ default:
context->recordError(Error(GL_INVALID_ENUM));
+ return nullptr;
}
- return NULL;
}
+
+ return nullptr;
}
void GL_APIENTRY GetTexParameterfv(GLenum target, GLenum pname, GLfloat* params)
@@ -2508,6 +2356,12 @@ void GL_APIENTRY GetTexParameterfv(GLenum target, GLenum pname, GLfloat* params)
Context *context = GetValidGlobalContext();
if (context)
{
+ if (!ValidTextureTarget(context, target))
+ {
+ context->recordError(Error(GL_INVALID_ENUM, "Invalid texture target"));
+ return;
+ }
+
Texture *texture = context->getTargetTexture(target);
if (!texture)
@@ -2519,16 +2373,16 @@ void GL_APIENTRY GetTexParameterfv(GLenum target, GLenum pname, GLfloat* params)
switch (pname)
{
case GL_TEXTURE_MAG_FILTER:
- *params = (GLfloat)texture->getSamplerState().magFilter;
+ *params = (GLfloat)texture->getMagFilter();
break;
case GL_TEXTURE_MIN_FILTER:
- *params = (GLfloat)texture->getSamplerState().minFilter;
+ *params = (GLfloat)texture->getMinFilter();
break;
case GL_TEXTURE_WRAP_S:
- *params = (GLfloat)texture->getSamplerState().wrapS;
+ *params = (GLfloat)texture->getWrapS();
break;
case GL_TEXTURE_WRAP_T:
- *params = (GLfloat)texture->getSamplerState().wrapT;
+ *params = (GLfloat)texture->getWrapT();
break;
case GL_TEXTURE_WRAP_R:
if (context->getClientVersion() < 3)
@@ -2536,11 +2390,11 @@ void GL_APIENTRY GetTexParameterfv(GLenum target, GLenum pname, GLfloat* params)
context->recordError(Error(GL_INVALID_ENUM));
return;
}
- *params = (GLfloat)texture->getSamplerState().wrapR;
+ *params = (GLfloat)texture->getWrapR();
break;
case GL_TEXTURE_IMMUTABLE_FORMAT:
// Exposed to ES2.0 through EXT_texture_storage, no client version validation.
- *params = (GLfloat)(texture->isImmutable() ? GL_TRUE : GL_FALSE);
+ *params = (GLfloat)(texture->getImmutableFormat() ? GL_TRUE : GL_FALSE);
break;
case GL_TEXTURE_IMMUTABLE_LEVELS:
if (context->getClientVersion() < 3)
@@ -2548,7 +2402,7 @@ void GL_APIENTRY GetTexParameterfv(GLenum target, GLenum pname, GLfloat* params)
context->recordError(Error(GL_INVALID_ENUM));
return;
}
- *params = (GLfloat)texture->immutableLevelCount();
+ *params = (GLfloat)texture->getImmutableLevels();
break;
case GL_TEXTURE_USAGE_ANGLE:
*params = (GLfloat)texture->getUsage();
@@ -2559,7 +2413,7 @@ void GL_APIENTRY GetTexParameterfv(GLenum target, GLenum pname, GLfloat* params)
context->recordError(Error(GL_INVALID_ENUM));
return;
}
- *params = (GLfloat)texture->getSamplerState().maxAnisotropy;
+ *params = (GLfloat)texture->getMaxAnisotropy();
break;
case GL_TEXTURE_SWIZZLE_R:
if (context->getClientVersion() < 3)
@@ -2567,7 +2421,7 @@ void GL_APIENTRY GetTexParameterfv(GLenum target, GLenum pname, GLfloat* params)
context->recordError(Error(GL_INVALID_ENUM));
return;
}
- *params = (GLfloat)texture->getSamplerState().swizzleRed;
+ *params = (GLfloat)texture->getSwizzleRed();
break;
case GL_TEXTURE_SWIZZLE_G:
if (context->getClientVersion() < 3)
@@ -2575,7 +2429,7 @@ void GL_APIENTRY GetTexParameterfv(GLenum target, GLenum pname, GLfloat* params)
context->recordError(Error(GL_INVALID_ENUM));
return;
}
- *params = (GLfloat)texture->getSamplerState().swizzleGreen;
+ *params = (GLfloat)texture->getSwizzleGreen();
break;
case GL_TEXTURE_SWIZZLE_B:
if (context->getClientVersion() < 3)
@@ -2583,7 +2437,7 @@ void GL_APIENTRY GetTexParameterfv(GLenum target, GLenum pname, GLfloat* params)
context->recordError(Error(GL_INVALID_ENUM));
return;
}
- *params = (GLfloat)texture->getSamplerState().swizzleBlue;
+ *params = (GLfloat)texture->getSwizzleBlue();
break;
case GL_TEXTURE_SWIZZLE_A:
if (context->getClientVersion() < 3)
@@ -2591,7 +2445,7 @@ void GL_APIENTRY GetTexParameterfv(GLenum target, GLenum pname, GLfloat* params)
context->recordError(Error(GL_INVALID_ENUM));
return;
}
- *params = (GLfloat)texture->getSamplerState().swizzleAlpha;
+ *params = (GLfloat)texture->getSwizzleAlpha();
break;
case GL_TEXTURE_BASE_LEVEL:
if (context->getClientVersion() < 3)
@@ -2599,7 +2453,7 @@ void GL_APIENTRY GetTexParameterfv(GLenum target, GLenum pname, GLfloat* params)
context->recordError(Error(GL_INVALID_ENUM));
return;
}
- *params = (GLfloat)texture->getSamplerState().baseLevel;
+ *params = (GLfloat)texture->getBaseLevel();
break;
case GL_TEXTURE_MAX_LEVEL:
if (context->getClientVersion() < 3)
@@ -2607,7 +2461,7 @@ void GL_APIENTRY GetTexParameterfv(GLenum target, GLenum pname, GLfloat* params)
context->recordError(Error(GL_INVALID_ENUM));
return;
}
- *params = (GLfloat)texture->getSamplerState().maxLevel;
+ *params = (GLfloat)texture->getMaxLevel();
break;
case GL_TEXTURE_MIN_LOD:
if (context->getClientVersion() < 3)
@@ -2640,6 +2494,12 @@ void GL_APIENTRY GetTexParameteriv(GLenum target, GLenum pname, GLint* params)
Context *context = GetValidGlobalContext();
if (context)
{
+ if (!ValidTextureTarget(context, target))
+ {
+ context->recordError(Error(GL_INVALID_ENUM, "Invalid texture target"));
+ return;
+ }
+
Texture *texture = context->getTargetTexture(target);
if (!texture)
@@ -2672,7 +2532,7 @@ void GL_APIENTRY GetTexParameteriv(GLenum target, GLenum pname, GLint* params)
break;
case GL_TEXTURE_IMMUTABLE_FORMAT:
// Exposed to ES2.0 through EXT_texture_storage, no client version validation.
- *params = texture->isImmutable() ? GL_TRUE : GL_FALSE;
+ *params = texture->getImmutableFormat() ? GL_TRUE : GL_FALSE;
break;
case GL_TEXTURE_IMMUTABLE_LEVELS:
if (context->getClientVersion() < 3)
@@ -2680,7 +2540,7 @@ void GL_APIENTRY GetTexParameteriv(GLenum target, GLenum pname, GLint* params)
context->recordError(Error(GL_INVALID_ENUM));
return;
}
- *params = static_cast<GLint>(texture->immutableLevelCount());
+ *params = static_cast<GLint>(texture->getImmutableLevels());
break;
case GL_TEXTURE_USAGE_ANGLE:
*params = texture->getUsage();
@@ -2691,7 +2551,7 @@ void GL_APIENTRY GetTexParameteriv(GLenum target, GLenum pname, GLint* params)
context->recordError(Error(GL_INVALID_ENUM));
return;
}
- *params = (GLint)texture->getSamplerState().maxAnisotropy;
+ *params = (GLint)texture->getMaxAnisotropy();
break;
case GL_TEXTURE_SWIZZLE_R:
if (context->getClientVersion() < 3)
@@ -2699,7 +2559,7 @@ void GL_APIENTRY GetTexParameteriv(GLenum target, GLenum pname, GLint* params)
context->recordError(Error(GL_INVALID_ENUM));
return;
}
- *params = texture->getSamplerState().swizzleRed;
+ *params = texture->getSwizzleRed();
break;
case GL_TEXTURE_SWIZZLE_G:
if (context->getClientVersion() < 3)
@@ -2707,7 +2567,7 @@ void GL_APIENTRY GetTexParameteriv(GLenum target, GLenum pname, GLint* params)
context->recordError(Error(GL_INVALID_ENUM));
return;
}
- *params = texture->getSamplerState().swizzleGreen;
+ *params = texture->getSwizzleGreen();
break;
case GL_TEXTURE_SWIZZLE_B:
if (context->getClientVersion() < 3)
@@ -2715,7 +2575,7 @@ void GL_APIENTRY GetTexParameteriv(GLenum target, GLenum pname, GLint* params)
context->recordError(Error(GL_INVALID_ENUM));
return;
}
- *params = texture->getSamplerState().swizzleBlue;
+ *params = texture->getSwizzleBlue();
break;
case GL_TEXTURE_SWIZZLE_A:
if (context->getClientVersion() < 3)
@@ -2723,7 +2583,7 @@ void GL_APIENTRY GetTexParameteriv(GLenum target, GLenum pname, GLint* params)
context->recordError(Error(GL_INVALID_ENUM));
return;
}
- *params = texture->getSamplerState().swizzleAlpha;
+ *params = texture->getSwizzleAlpha();
break;
case GL_TEXTURE_BASE_LEVEL:
if (context->getClientVersion() < 3)
@@ -2731,7 +2591,7 @@ void GL_APIENTRY GetTexParameteriv(GLenum target, GLenum pname, GLint* params)
context->recordError(Error(GL_INVALID_ENUM));
return;
}
- *params = texture->getSamplerState().baseLevel;
+ *params = texture->getBaseLevel();
break;
case GL_TEXTURE_MAX_LEVEL:
if (context->getClientVersion() < 3)
@@ -2739,7 +2599,7 @@ void GL_APIENTRY GetTexParameteriv(GLenum target, GLenum pname, GLint* params)
context->recordError(Error(GL_INVALID_ENUM));
return;
}
- *params = texture->getSamplerState().maxLevel;
+ *params = texture->getMaxLevel();
break;
case GL_TEXTURE_MIN_LOD:
if (context->getClientVersion() < 3)
@@ -2747,7 +2607,7 @@ void GL_APIENTRY GetTexParameteriv(GLenum target, GLenum pname, GLint* params)
context->recordError(Error(GL_INVALID_ENUM));
return;
}
- *params = (GLint)texture->getSamplerState().minLod;
+ *params = (GLint)texture->getMinLod();
break;
case GL_TEXTURE_MAX_LOD:
if (context->getClientVersion() < 3)
@@ -2755,7 +2615,7 @@ void GL_APIENTRY GetTexParameteriv(GLenum target, GLenum pname, GLint* params)
context->recordError(Error(GL_INVALID_ENUM));
return;
}
- *params = (GLint)texture->getSamplerState().maxLod;
+ *params = (GLint)texture->getMaxLod();
break;
default:
@@ -2815,20 +2675,11 @@ GLint GL_APIENTRY GetUniformLocation(GLuint program, const GLchar* name)
return -1;
}
- Program *programObject = context->getProgram(program);
+ Program *programObject = GetValidProgram(context, program);
if (!programObject)
{
- if (context->getShader(program))
- {
- context->recordError(Error(GL_INVALID_OPERATION));
- return -1;
- }
- else
- {
- context->recordError(Error(GL_INVALID_VALUE));
- return -1;
- }
+ return -1;
}
if (!programObject->isLinked())
@@ -3122,20 +2973,10 @@ void GL_APIENTRY LinkProgram(GLuint program)
Context *context = GetValidGlobalContext();
if (context)
{
- Program *programObject = context->getProgram(program);
-
+ Program *programObject = GetValidProgram(context, program);
if (!programObject)
{
- if (context->getShader(program))
- {
- context->recordError(Error(GL_INVALID_OPERATION));
- return;
- }
- else
- {
- context->recordError(Error(GL_INVALID_VALUE));
- return;
- }
+ return;
}
Error error = programObject->link(context->getData());
@@ -3160,14 +3001,28 @@ void GL_APIENTRY PixelStorei(GLenum pname, GLint param)
{
case GL_UNPACK_IMAGE_HEIGHT:
case GL_UNPACK_SKIP_IMAGES:
+ context->recordError(Error(GL_INVALID_ENUM));
+ return;
+
case GL_UNPACK_ROW_LENGTH:
case GL_UNPACK_SKIP_ROWS:
case GL_UNPACK_SKIP_PIXELS:
+ if (!context->getExtensions().unpackSubimage)
+ {
+ context->recordError(Error(GL_INVALID_ENUM));
+ return;
+ }
+ break;
+
case GL_PACK_ROW_LENGTH:
case GL_PACK_SKIP_ROWS:
case GL_PACK_SKIP_PIXELS:
- context->recordError(Error(GL_INVALID_ENUM));
- return;
+ if (!context->getExtensions().packSubimage)
+ {
+ context->recordError(Error(GL_INVALID_ENUM));
+ return;
+ }
+ break;
}
}
@@ -3206,43 +3061,43 @@ void GL_APIENTRY PixelStorei(GLenum pname, GLint param)
break;
case GL_UNPACK_ROW_LENGTH:
- ASSERT(context->getClientVersion() >= 3);
+ ASSERT((context->getClientVersion() >= 3) || context->getExtensions().unpackSubimage);
state.setUnpackRowLength(param);
break;
case GL_UNPACK_IMAGE_HEIGHT:
ASSERT(context->getClientVersion() >= 3);
- state.getUnpackState().imageHeight = param;
+ state.setUnpackImageHeight(param);
break;
case GL_UNPACK_SKIP_IMAGES:
- ASSERT(context->getClientVersion() >= 3);
- state.getUnpackState().skipImages = param;
+ ASSERT(context->getClientVersion() >= 3);
+ state.setUnpackSkipImages(param);
break;
case GL_UNPACK_SKIP_ROWS:
- ASSERT(context->getClientVersion() >= 3);
- state.getUnpackState().skipRows = param;
+ ASSERT((context->getClientVersion() >= 3) || context->getExtensions().unpackSubimage);
+ state.setUnpackSkipRows(param);
break;
case GL_UNPACK_SKIP_PIXELS:
- ASSERT(context->getClientVersion() >= 3);
- state.getUnpackState().skipPixels = param;
+ ASSERT((context->getClientVersion() >= 3) || context->getExtensions().unpackSubimage);
+ state.setUnpackSkipPixels(param);
break;
case GL_PACK_ROW_LENGTH:
- ASSERT(context->getClientVersion() >= 3);
- state.getPackState().rowLength = param;
+ ASSERT((context->getClientVersion() >= 3) || context->getExtensions().packSubimage);
+ state.setPackRowLength(param);
break;
case GL_PACK_SKIP_ROWS:
- ASSERT(context->getClientVersion() >= 3);
- state.getPackState().skipRows = param;
+ ASSERT((context->getClientVersion() >= 3) || context->getExtensions().packSubimage);
+ state.setPackSkipRows(param);
break;
case GL_PACK_SKIP_PIXELS:
- ASSERT(context->getClientVersion() >= 3);
- state.getPackState().skipPixels = param;
+ ASSERT((context->getClientVersion() >= 3) || context->getExtensions().packSubimage);
+ state.setPackSkipPixels(param);
break;
default:
@@ -3273,28 +3128,13 @@ void GL_APIENTRY ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height,
Context *context = GetValidGlobalContext();
if (context)
{
- if (width < 0 || height < 0)
+ if (!context->skipValidation() &&
+ !ValidateReadPixels(context, x, y, width, height, format, type, pixels))
{
- context->recordError(Error(GL_INVALID_VALUE));
return;
}
- if (!ValidateReadPixelsParameters(context, x, y, width, height,
- format, type, NULL, pixels))
- {
- return;
- }
-
- Framebuffer *framebufferObject = context->getState().getReadFramebuffer();
- ASSERT(framebufferObject);
-
- Rectangle area(x, y, width, height);
- Error error = framebufferObject->readPixels(context->getState(), area, format, type, pixels);
- if (error.isError())
- {
- context->recordError(error);
- return;
- }
+ context->readPixels(x, y, width, height, format, type, pixels);
}
}
@@ -3404,22 +3244,11 @@ void GL_APIENTRY ShaderSource(GLuint shader, GLsizei count, const GLchar* const*
return;
}
- Shader *shaderObject = context->getShader(shader);
-
+ Shader *shaderObject = GetValidShader(context, shader);
if (!shaderObject)
{
- if (context->getProgram(shader))
- {
- context->recordError(Error(GL_INVALID_OPERATION));
- return;
- }
- else
- {
- context->recordError(Error(GL_INVALID_VALUE));
- return;
- }
+ return;
}
-
shaderObject->setSource(count, string, length);
}
}
@@ -3619,15 +3448,16 @@ void GL_APIENTRY TexImage2D(GLenum target, GLint level, GLint internalformat, GL
}
if (context->getClientVersion() >= 3 &&
- !ValidateES3TexImageParameters(context, target, level, internalformat, false, false,
- 0, 0, 0, width, height, 1, border, format, type, pixels))
+ !ValidateES3TexImage2DParameters(context, target, level, internalformat, false, false,
+ 0, 0, 0, width, height, 1, border, format, type,
+ pixels))
{
return;
}
Extents size(width, height, 1);
Texture *texture = context->getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target);
- Error error = texture->setImage(target, level, internalformat, size, format, type, context->getState().getUnpackState(),
+ Error error = texture->setImage(context, target, level, internalformat, size, format, type,
reinterpret_cast<const uint8_t *>(pixels));
if (error.isError())
{
@@ -3644,6 +3474,12 @@ void GL_APIENTRY TexParameterf(GLenum target, GLenum pname, GLfloat param)
Context *context = GetValidGlobalContext();
if (context)
{
+ if (!ValidTextureTarget(context, target))
+ {
+ context->recordError(Error(GL_INVALID_ENUM, "Invalid texture target"));
+ return;
+ }
+
if (!ValidateTexParamParameters(context, pname, static_cast<GLint>(param)))
{
return;
@@ -3657,27 +3493,29 @@ void GL_APIENTRY TexParameterf(GLenum target, GLenum pname, GLfloat param)
return;
}
+ // clang-format off
switch (pname)
{
- case GL_TEXTURE_WRAP_S: texture->getSamplerState().wrapS = uiround<GLenum>(param); break;
- case GL_TEXTURE_WRAP_T: texture->getSamplerState().wrapT = uiround<GLenum>(param); break;
- case GL_TEXTURE_WRAP_R: texture->getSamplerState().wrapR = uiround<GLenum>(param); break;
- case GL_TEXTURE_MIN_FILTER: texture->getSamplerState().minFilter = uiround<GLenum>(param); break;
- case GL_TEXTURE_MAG_FILTER: texture->getSamplerState().magFilter = uiround<GLenum>(param); break;
- case GL_TEXTURE_USAGE_ANGLE: texture->setUsage(uiround<GLenum>(param)); break;
- case GL_TEXTURE_MAX_ANISOTROPY_EXT: texture->getSamplerState().maxAnisotropy = std::min(param, context->getExtensions().maxTextureAnisotropy); break;
- case GL_TEXTURE_COMPARE_MODE: texture->getSamplerState().compareMode = uiround<GLenum>(param); break;
- case GL_TEXTURE_COMPARE_FUNC: texture->getSamplerState().compareFunc = uiround<GLenum>(param); break;
- case GL_TEXTURE_SWIZZLE_R: texture->getSamplerState().swizzleRed = uiround<GLenum>(param); break;
- case GL_TEXTURE_SWIZZLE_G: texture->getSamplerState().swizzleGreen = uiround<GLenum>(param); break;
- case GL_TEXTURE_SWIZZLE_B: texture->getSamplerState().swizzleBlue = uiround<GLenum>(param); break;
- case GL_TEXTURE_SWIZZLE_A: texture->getSamplerState().swizzleAlpha = uiround<GLenum>(param); break;
- case GL_TEXTURE_BASE_LEVEL: texture->getSamplerState().baseLevel = iround<GLint>(param); break;
- case GL_TEXTURE_MAX_LEVEL: texture->getSamplerState().maxLevel = iround<GLint>(param); break;
- case GL_TEXTURE_MIN_LOD: texture->getSamplerState().minLod = param; break;
- case GL_TEXTURE_MAX_LOD: texture->getSamplerState().maxLod = param; break;
+ case GL_TEXTURE_WRAP_S: texture->setWrapS(uiround<GLenum>(param)); break;
+ case GL_TEXTURE_WRAP_T: texture->setWrapT(uiround<GLenum>(param)); break;
+ case GL_TEXTURE_WRAP_R: texture->setWrapR(uiround<GLenum>(param)); break;
+ case GL_TEXTURE_MIN_FILTER: texture->setMinFilter(uiround<GLenum>(param)); break;
+ case GL_TEXTURE_MAG_FILTER: texture->setMagFilter(uiround<GLenum>(param)); break;
+ case GL_TEXTURE_USAGE_ANGLE: texture->setUsage(uiround<GLenum>(param)); break;
+ case GL_TEXTURE_MAX_ANISOTROPY_EXT: texture->setMaxAnisotropy(std::min(param, context->getExtensions().maxTextureAnisotropy)); break;
+ case GL_TEXTURE_COMPARE_MODE: texture->setCompareMode(uiround<GLenum>(param)); break;
+ case GL_TEXTURE_COMPARE_FUNC: texture->setCompareFunc(uiround<GLenum>(param)); break;
+ case GL_TEXTURE_SWIZZLE_R: texture->setSwizzleRed(uiround<GLenum>(param)); break;
+ case GL_TEXTURE_SWIZZLE_G: texture->setSwizzleGreen(uiround<GLenum>(param)); break;
+ case GL_TEXTURE_SWIZZLE_B: texture->setSwizzleBlue(uiround<GLenum>(param)); break;
+ case GL_TEXTURE_SWIZZLE_A: texture->setSwizzleAlpha(uiround<GLenum>(param)); break;
+ case GL_TEXTURE_BASE_LEVEL: texture->setBaseLevel(uiround<GLuint>(param)); break;
+ case GL_TEXTURE_MAX_LEVEL: texture->setMaxLevel(uiround<GLuint>(param)); break;
+ case GL_TEXTURE_MIN_LOD: texture->setMinLod(param); break;
+ case GL_TEXTURE_MAX_LOD: texture->setMaxLod(param); break;
default: UNREACHABLE(); break;
}
+ // clang-format on
}
}
@@ -3693,6 +3531,12 @@ void GL_APIENTRY TexParameteri(GLenum target, GLenum pname, GLint param)
Context *context = GetValidGlobalContext();
if (context)
{
+ if (!ValidTextureTarget(context, target))
+ {
+ context->recordError(Error(GL_INVALID_ENUM, "Invalid Texture target"));
+ return;
+ }
+
if (!ValidateTexParamParameters(context, pname, param))
{
return;
@@ -3706,27 +3550,29 @@ void GL_APIENTRY TexParameteri(GLenum target, GLenum pname, GLint param)
return;
}
+ // clang-format off
switch (pname)
{
- case GL_TEXTURE_WRAP_S: texture->getSamplerState().wrapS = (GLenum)param; break;
- case GL_TEXTURE_WRAP_T: texture->getSamplerState().wrapT = (GLenum)param; break;
- case GL_TEXTURE_WRAP_R: texture->getSamplerState().wrapR = (GLenum)param; break;
- case GL_TEXTURE_MIN_FILTER: texture->getSamplerState().minFilter = (GLenum)param; break;
- case GL_TEXTURE_MAG_FILTER: texture->getSamplerState().magFilter = (GLenum)param; break;
- case GL_TEXTURE_USAGE_ANGLE: texture->setUsage((GLenum)param); break;
- case GL_TEXTURE_MAX_ANISOTROPY_EXT: texture->getSamplerState().maxAnisotropy = std::min((float)param, context->getExtensions().maxTextureAnisotropy); break;
- case GL_TEXTURE_COMPARE_MODE: texture->getSamplerState().compareMode = (GLenum)param; break;
- case GL_TEXTURE_COMPARE_FUNC: texture->getSamplerState().compareFunc = (GLenum)param; break;
- case GL_TEXTURE_SWIZZLE_R: texture->getSamplerState().swizzleRed = (GLenum)param; break;
- case GL_TEXTURE_SWIZZLE_G: texture->getSamplerState().swizzleGreen = (GLenum)param; break;
- case GL_TEXTURE_SWIZZLE_B: texture->getSamplerState().swizzleBlue = (GLenum)param; break;
- case GL_TEXTURE_SWIZZLE_A: texture->getSamplerState().swizzleAlpha = (GLenum)param; break;
- case GL_TEXTURE_BASE_LEVEL: texture->getSamplerState().baseLevel = param; break;
- case GL_TEXTURE_MAX_LEVEL: texture->getSamplerState().maxLevel = param; break;
- case GL_TEXTURE_MIN_LOD: texture->getSamplerState().minLod = (GLfloat)param; break;
- case GL_TEXTURE_MAX_LOD: texture->getSamplerState().maxLod = (GLfloat)param; break;
+ case GL_TEXTURE_WRAP_S: texture->setWrapS(static_cast<GLenum>(param)); break;
+ case GL_TEXTURE_WRAP_T: texture->setWrapT(static_cast<GLenum>(param)); break;
+ case GL_TEXTURE_WRAP_R: texture->setWrapR(static_cast<GLenum>(param)); break;
+ case GL_TEXTURE_MIN_FILTER: texture->setMinFilter(static_cast<GLenum>(param)); break;
+ case GL_TEXTURE_MAG_FILTER: texture->setMagFilter(static_cast<GLenum>(param)); break;
+ case GL_TEXTURE_USAGE_ANGLE: texture->setUsage(static_cast<GLenum>(param)); break;
+ case GL_TEXTURE_MAX_ANISOTROPY_EXT: texture->setMaxAnisotropy(std::min(static_cast<GLfloat>(param), context->getExtensions().maxTextureAnisotropy)); break;
+ case GL_TEXTURE_COMPARE_MODE: texture->setCompareMode(static_cast<GLenum>(param)); break;
+ case GL_TEXTURE_COMPARE_FUNC: texture->setCompareFunc(static_cast<GLenum>(param)); break;
+ case GL_TEXTURE_SWIZZLE_R: texture->setSwizzleRed(static_cast<GLenum>(param)); break;
+ case GL_TEXTURE_SWIZZLE_G: texture->setSwizzleGreen(static_cast<GLenum>(param)); break;
+ case GL_TEXTURE_SWIZZLE_B: texture->setSwizzleBlue(static_cast<GLenum>(param)); break;
+ case GL_TEXTURE_SWIZZLE_A: texture->setSwizzleAlpha(static_cast<GLenum>(param)); break;
+ case GL_TEXTURE_BASE_LEVEL: texture->setBaseLevel(static_cast<GLuint>(param)); break;
+ case GL_TEXTURE_MAX_LEVEL: texture->setMaxLevel(static_cast<GLuint>(param)); break;
+ case GL_TEXTURE_MIN_LOD: texture->setMinLod(static_cast<GLfloat>(param)); break;
+ case GL_TEXTURE_MAX_LOD: texture->setMaxLod(static_cast<GLfloat>(param)); break;
default: UNREACHABLE(); break;
}
+ // clang-format on
}
}
@@ -3754,8 +3600,8 @@ void GL_APIENTRY TexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint
}
if (context->getClientVersion() >= 3 &&
- !ValidateES3TexImageParameters(context, target, level, GL_NONE, false, true,
- xoffset, yoffset, 0, width, height, 1, 0, format, type, pixels))
+ !ValidateES3TexImage2DParameters(context, target, level, GL_NONE, false, true, xoffset,
+ yoffset, 0, width, height, 1, 0, format, type, pixels))
{
return;
}
@@ -3768,7 +3614,7 @@ void GL_APIENTRY TexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint
Box area(xoffset, yoffset, 0, width, height, 1);
Texture *texture = context->getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target);
- Error error = texture->setSubImage(target, level, area, format, type, context->getState().getUnpackState(),
+ Error error = texture->setSubImage(context, target, level, area, format, type,
reinterpret_cast<const uint8_t *>(pixels));
if (error.isError())
{
@@ -4060,20 +3906,11 @@ void GL_APIENTRY ValidateProgram(GLuint program)
Context *context = GetValidGlobalContext();
if (context)
{
- Program *programObject = context->getProgram(program);
+ Program *programObject = GetValidProgram(context, program);
if (!programObject)
{
- if (context->getShader(program))
- {
- context->recordError(Error(GL_INVALID_OPERATION));
- return;
- }
- else
- {
- context->recordError(Error(GL_INVALID_VALUE));
- return;
- }
+ return;
}
programObject->validate(context->getCaps());
diff --git a/src/3rdparty/angle/src/libGLESv2/entry_points_gles_2_0_ext.cpp b/src/3rdparty/angle/src/libGLESv2/entry_points_gles_2_0_ext.cpp
index d41c5a4da5..7df6fcb0cd 100644
--- a/src/3rdparty/angle/src/libGLESv2/entry_points_gles_2_0_ext.cpp
+++ b/src/3rdparty/angle/src/libGLESv2/entry_points_gles_2_0_ext.cpp
@@ -27,6 +27,57 @@
namespace gl
{
+void GL_APIENTRY GenQueriesEXT(GLsizei n, GLuint *ids)
+{
+ EVENT("(GLsizei n = %d, GLuint* ids = 0x%0.8p)", n, ids);
+
+ Context *context = GetValidGlobalContext();
+ if (context)
+ {
+ if (!ValidateGenQueriesEXT(context, n, ids))
+ {
+ return;
+ }
+
+ for (GLsizei i = 0; i < n; i++)
+ {
+ ids[i] = context->createQuery();
+ }
+ }
+}
+
+void GL_APIENTRY DeleteQueriesEXT(GLsizei n, const GLuint *ids)
+{
+ EVENT("(GLsizei n = %d, const GLuint *ids = 0x%0.8p)", n, ids);
+
+ Context *context = GetValidGlobalContext();
+ if (context)
+ {
+ if (!ValidateDeleteQueriesEXT(context, n, ids))
+ {
+ return;
+ }
+
+ for (int i = 0; i < n; i++)
+ {
+ context->deleteQuery(ids[i]);
+ }
+ }
+}
+
+GLboolean GL_APIENTRY IsQueryEXT(GLuint id)
+{
+ EVENT("(GLuint id = %d)", id);
+
+ Context *context = GetValidGlobalContext();
+ if (context)
+ {
+ return (context->getQuery(id, false, GL_NONE) != NULL) ? GL_TRUE : GL_FALSE;
+ }
+
+ return GL_FALSE;
+}
+
void GL_APIENTRY BeginQueryEXT(GLenum target, GLuint id)
{
EVENT("(GLenum target = 0x%X, GLuint %d)", target, id);
@@ -34,7 +85,7 @@ void GL_APIENTRY BeginQueryEXT(GLenum target, GLuint id)
Context *context = GetValidGlobalContext();
if (context)
{
- if (!ValidateBeginQuery(context, target, id))
+ if (!ValidateBeginQueryEXT(context, target, id))
{
return;
}
@@ -48,59 +99,78 @@ void GL_APIENTRY BeginQueryEXT(GLenum target, GLuint id)
}
}
-void GL_APIENTRY DeleteFencesNV(GLsizei n, const GLuint* fences)
+void GL_APIENTRY EndQueryEXT(GLenum target)
{
- EVENT("(GLsizei n = %d, const GLuint* fences = 0x%0.8p)", n, fences);
+ EVENT("GLenum target = 0x%X)", target);
Context *context = GetValidGlobalContext();
if (context)
{
- if (n < 0)
+ if (!ValidateEndQueryEXT(context, target))
{
- context->recordError(Error(GL_INVALID_VALUE));
return;
}
- for (int i = 0; i < n; i++)
+ Error error = context->endQuery(target);
+ if (error.isError())
{
- context->deleteFenceNV(fences[i]);
+ context->recordError(error);
+ return;
}
}
}
-void GL_APIENTRY DeleteQueriesEXT(GLsizei n, const GLuint *ids)
+void GL_APIENTRY QueryCounterEXT(GLuint id, GLenum target)
{
- EVENT("(GLsizei n = %d, const GLuint *ids = 0x%0.8p)", n, ids);
+ EVENT("GLuint id = %d, GLenum target = 0x%X)", id, target);
Context *context = GetValidGlobalContext();
if (context)
{
- if (n < 0)
+ if (!ValidateQueryCounterEXT(context, id, target))
{
- context->recordError(Error(GL_INVALID_VALUE));
return;
}
- for (int i = 0; i < n; i++)
+ Error error = context->queryCounter(id, target);
+ if (error.isError())
{
- context->deleteQuery(ids[i]);
+ context->recordError(error);
+ return;
}
}
}
-void GL_APIENTRY DrawArraysInstancedANGLE(GLenum mode, GLint first, GLsizei count, GLsizei primcount)
+void GL_APIENTRY GetQueryivEXT(GLenum target, GLenum pname, GLint *params)
{
- EVENT("(GLenum mode = 0x%X, GLint first = %d, GLsizei count = %d, GLsizei primcount = %d)", mode, first, count, primcount);
+ EVENT("GLenum target = 0x%X, GLenum pname = 0x%X, GLint *params = 0x%0.8p)", target, pname,
+ params);
Context *context = GetValidGlobalContext();
if (context)
{
- if (!ValidateDrawArraysInstancedANGLE(context, mode, first, count, primcount))
+ if (!ValidateGetQueryivEXT(context, target, pname, params))
{
return;
}
- Error error = context->drawArrays(mode, first, count, primcount);
+ context->getQueryiv(target, pname, params);
+ }
+}
+
+void GL_APIENTRY GetQueryObjectivEXT(GLuint id, GLenum pname, GLint *params)
+{
+ EVENT("(GLuint id = %d, GLenum pname = 0x%X, GLuint *params = 0x%0.8p)", id, pname, params);
+
+ Context *context = GetValidGlobalContext();
+ if (context)
+ {
+ if (!ValidateGetQueryObjectivEXT(context, id, pname, params))
+ {
+ return;
+ }
+
+ Error error = context->getQueryObjectiv(id, pname, params);
if (error.isError())
{
context->recordError(error);
@@ -109,21 +179,19 @@ void GL_APIENTRY DrawArraysInstancedANGLE(GLenum mode, GLint first, GLsizei coun
}
}
-void GL_APIENTRY DrawElementsInstancedANGLE(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount)
+void GL_APIENTRY GetQueryObjectuivEXT(GLuint id, GLenum pname, GLuint *params)
{
- EVENT("(GLenum mode = 0x%X, GLsizei count = %d, GLenum type = 0x%X, const GLvoid* indices = 0x%0.8p, GLsizei primcount = %d)",
- mode, count, type, indices, primcount);
+ EVENT("(GLuint id = %d, GLenum pname = 0x%X, GLuint *params = 0x%0.8p)", id, pname, params);
Context *context = GetValidGlobalContext();
if (context)
{
- rx::RangeUI indexRange;
- if (!ValidateDrawElementsInstancedANGLE(context, mode, count, type, indices, primcount, &indexRange))
+ if (!ValidateGetQueryObjectuivEXT(context, id, pname, params))
{
return;
}
- Error error = context->drawElements(mode, count, type, indices, primcount, indexRange);
+ Error error = context->getQueryObjectuiv(id, pname, params);
if (error.isError())
{
context->recordError(error);
@@ -132,19 +200,19 @@ void GL_APIENTRY DrawElementsInstancedANGLE(GLenum mode, GLsizei count, GLenum t
}
}
-void GL_APIENTRY EndQueryEXT(GLenum target)
+void GL_APIENTRY GetQueryObjecti64vEXT(GLuint id, GLenum pname, GLint64 *params)
{
- EVENT("GLenum target = 0x%X)", target);
+ EVENT("(GLuint id = %d, GLenum pname = 0x%X, GLuint *params = 0x%0.16p)", id, pname, params);
Context *context = GetValidGlobalContext();
if (context)
{
- if (!ValidateEndQuery(context, target))
+ if (!ValidateGetQueryObjecti64vEXT(context, id, pname, params))
{
return;
}
- Error error = context->endQuery(target);
+ Error error = context->getQueryObjecti64v(id, pname, params);
if (error.isError())
{
context->recordError(error);
@@ -153,34 +221,30 @@ void GL_APIENTRY EndQueryEXT(GLenum target)
}
}
-void GL_APIENTRY FinishFenceNV(GLuint fence)
+void GL_APIENTRY GetQueryObjectui64vEXT(GLuint id, GLenum pname, GLuint64 *params)
{
- EVENT("(GLuint fence = %d)", fence);
+ EVENT("(GLuint id = %d, GLenum pname = 0x%X, GLuint *params = 0x%0.16p)", id, pname, params);
Context *context = GetValidGlobalContext();
if (context)
{
- FenceNV *fenceObject = context->getFenceNV(fence);
-
- if (fenceObject == NULL)
+ if (!ValidateGetQueryObjectui64vEXT(context, id, pname, params))
{
- context->recordError(Error(GL_INVALID_OPERATION));
return;
}
- if (fenceObject->isFence() != GL_TRUE)
+ Error error = context->getQueryObjectui64v(id, pname, params);
+ if (error.isError())
{
- context->recordError(Error(GL_INVALID_OPERATION));
+ context->recordError(error);
return;
}
-
- fenceObject->finishFence();
}
}
-void GL_APIENTRY GenFencesNV(GLsizei n, GLuint* fences)
+void GL_APIENTRY DeleteFencesNV(GLsizei n, const GLuint *fences)
{
- EVENT("(GLsizei n = %d, GLuint* fences = 0x%0.8p)", n, fences);
+ EVENT("(GLsizei n = %d, const GLuint* fences = 0x%0.8p)", n, fences);
Context *context = GetValidGlobalContext();
if (context)
@@ -193,14 +257,95 @@ void GL_APIENTRY GenFencesNV(GLsizei n, GLuint* fences)
for (int i = 0; i < n; i++)
{
- fences[i] = context->createFenceNV();
+ context->deleteFenceNV(fences[i]);
}
}
}
-void GL_APIENTRY GenQueriesEXT(GLsizei n, GLuint* ids)
+void GL_APIENTRY DrawArraysInstancedANGLE(GLenum mode,
+ GLint first,
+ GLsizei count,
+ GLsizei primcount)
{
- EVENT("(GLsizei n = %d, GLuint* ids = 0x%0.8p)", n, ids);
+ EVENT("(GLenum mode = 0x%X, GLint first = %d, GLsizei count = %d, GLsizei primcount = %d)",
+ mode, first, count, primcount);
+
+ Context *context = GetValidGlobalContext();
+ if (context)
+ {
+ if (!ValidateDrawArraysInstancedANGLE(context, mode, first, count, primcount))
+ {
+ return;
+ }
+
+ Error error = context->drawArraysInstanced(mode, first, count, primcount);
+ if (error.isError())
+ {
+ context->recordError(error);
+ return;
+ }
+ }
+}
+
+void GL_APIENTRY DrawElementsInstancedANGLE(GLenum mode,
+ GLsizei count,
+ GLenum type,
+ const GLvoid *indices,
+ GLsizei primcount)
+{
+ EVENT(
+ "(GLenum mode = 0x%X, GLsizei count = %d, GLenum type = 0x%X, const GLvoid* indices = "
+ "0x%0.8p, GLsizei primcount = %d)",
+ mode, count, type, indices, primcount);
+
+ Context *context = GetValidGlobalContext();
+ if (context)
+ {
+ IndexRange indexRange;
+ if (!ValidateDrawElementsInstancedANGLE(context, mode, count, type, indices, primcount,
+ &indexRange))
+ {
+ return;
+ }
+
+ Error error =
+ context->drawElementsInstanced(mode, count, type, indices, primcount, indexRange);
+ if (error.isError())
+ {
+ context->recordError(error);
+ return;
+ }
+ }
+}
+
+void GL_APIENTRY FinishFenceNV(GLuint fence)
+{
+ EVENT("(GLuint fence = %d)", fence);
+
+ Context *context = GetValidGlobalContext();
+ if (context)
+ {
+ FenceNV *fenceObject = context->getFenceNV(fence);
+
+ if (fenceObject == NULL)
+ {
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return;
+ }
+
+ if (fenceObject->isSet() != GL_TRUE)
+ {
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return;
+ }
+
+ fenceObject->finish();
+ }
+}
+
+void GL_APIENTRY GenFencesNV(GLsizei n, GLuint *fences)
+{
+ EVENT("(GLsizei n = %d, GLuint* fences = 0x%0.8p)", n, fences);
Context *context = GetValidGlobalContext();
if (context)
@@ -211,9 +356,9 @@ void GL_APIENTRY GenQueriesEXT(GLsizei n, GLuint* ids)
return;
}
- for (GLsizei i = 0; i < n; i++)
+ for (int i = 0; i < n; i++)
{
- ids[i] = context->createQuery();
+ fences[i] = context->createFenceNV();
}
}
}
@@ -233,7 +378,7 @@ void GL_APIENTRY GetFenceivNV(GLuint fence, GLenum pname, GLint *params)
return;
}
- if (fenceObject->isFence() != GL_TRUE)
+ if (fenceObject->isSet() != GL_TRUE)
{
context->recordError(Error(GL_INVALID_OPERATION));
return;
@@ -249,7 +394,7 @@ void GL_APIENTRY GetFenceivNV(GLuint fence, GLenum pname, GLint *params)
GLboolean status = GL_TRUE;
if (fenceObject->getStatus() != GL_TRUE)
{
- Error error = fenceObject->testFence(&status);
+ Error error = fenceObject->test(&status);
if (error.isError())
{
context->recordError(error);
@@ -289,84 +434,6 @@ GLenum GL_APIENTRY GetGraphicsResetStatusEXT(void)
return GL_NO_ERROR;
}
-void GL_APIENTRY GetQueryivEXT(GLenum target, GLenum pname, GLint *params)
-{
- EVENT("GLenum target = 0x%X, GLenum pname = 0x%X, GLint *params = 0x%0.8p)", target, pname, params);
-
- Context *context = GetValidGlobalContext();
- if (context)
- {
- if (!ValidQueryType(context, target))
- {
- context->recordError(Error(GL_INVALID_ENUM));
- return;
- }
-
- switch (pname)
- {
- case GL_CURRENT_QUERY_EXT:
- params[0] = context->getState().getActiveQueryId(target);
- break;
-
- default:
- context->recordError(Error(GL_INVALID_ENUM));
- return;
- }
- }
-}
-
-void GL_APIENTRY GetQueryObjectuivEXT(GLuint id, GLenum pname, GLuint *params)
-{
- EVENT("(GLuint id = %d, GLenum pname = 0x%X, GLuint *params = 0x%0.8p)", id, pname, params);
-
- Context *context = GetValidGlobalContext();
- if (context)
- {
- Query *queryObject = context->getQuery(id, false, GL_NONE);
-
- if (!queryObject)
- {
- context->recordError(Error(GL_INVALID_OPERATION));
- return;
- }
-
- if (context->getState().getActiveQueryId(queryObject->getType()) == id)
- {
- context->recordError(Error(GL_INVALID_OPERATION));
- return;
- }
-
- switch(pname)
- {
- case GL_QUERY_RESULT_EXT:
- {
- Error error = queryObject->getResult(params);
- if (error.isError())
- {
- context->recordError(error);
- return;
- }
- }
- break;
-
- case GL_QUERY_RESULT_AVAILABLE_EXT:
- {
- Error error = queryObject->isResultAvailable(params);
- if (error.isError())
- {
- context->recordError(error);
- return;
- }
- }
- break;
-
- default:
- context->recordError(Error(GL_INVALID_ENUM));
- return;
- }
- }
-}
-
void GL_APIENTRY GetTranslatedShaderSourceANGLE(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source)
{
EVENT("(GLuint shader = %d, GLsizei bufsize = %d, GLsizei* length = 0x%0.8p, GLchar* source = 0x%0.8p)",
@@ -389,7 +456,6 @@ void GL_APIENTRY GetTranslatedShaderSourceANGLE(GLuint shader, GLsizei bufsize,
return;
}
- // Only returns extra info if ANGLE_GENERATE_SHADER_DEBUG_INFO is defined
shaderObject->getTranslatedSourceWithDebugInfo(bufsize, length, source);
}
}
@@ -448,20 +514,9 @@ GLboolean GL_APIENTRY IsFenceNV(GLuint fence)
return GL_FALSE;
}
- return fenceObject->isFence();
- }
-
- return GL_FALSE;
-}
-
-GLboolean GL_APIENTRY IsQueryEXT(GLuint id)
-{
- EVENT("(GLuint id = %d)", id);
-
- Context *context = GetValidGlobalContext();
- if (context)
- {
- return (context->getQuery(id, false, GL_NONE) != NULL) ? GL_TRUE : GL_FALSE;
+ // GL_NV_fence spec:
+ // A name returned by GenFencesNV, but not yet set via SetFenceNV, is not the name of an existing fence.
+ return fenceObject->isSet();
}
return GL_FALSE;
@@ -478,28 +533,13 @@ void GL_APIENTRY ReadnPixelsEXT(GLint x, GLint y, GLsizei width, GLsizei height,
Context *context = GetValidGlobalContext();
if (context)
{
- if (width < 0 || height < 0 || bufSize < 0)
- {
- context->recordError(Error(GL_INVALID_VALUE));
- return;
- }
-
- if (!ValidateReadPixelsParameters(context, x, y, width, height,
- format, type, &bufSize, data))
+ if (!context->skipValidation() &&
+ !ValidateReadnPixelsEXT(context, x, y, width, height, format, type, bufSize, data))
{
return;
}
- Framebuffer *framebufferObject = context->getState().getReadFramebuffer();
- ASSERT(framebufferObject);
-
- Rectangle area(x, y, width, height);
- Error error = framebufferObject->readPixels(context->getState(), area, format, type, data);
- if (error.isError())
- {
- context->recordError(error);
- return;
- }
+ context->readPixels(x, y, width, height, format, type, data);
}
}
@@ -548,7 +588,7 @@ void GL_APIENTRY SetFenceNV(GLuint fence, GLenum condition)
return;
}
- Error error = fenceObject->setFence(condition);
+ Error error = fenceObject->set(condition);
if (error.isError())
{
context->recordError(error);
@@ -572,14 +612,14 @@ GLboolean GL_APIENTRY TestFenceNV(GLuint fence)
return GL_TRUE;
}
- if (fenceObject->isFence() != GL_TRUE)
+ if (fenceObject->isSet() != GL_TRUE)
{
context->recordError(Error(GL_INVALID_OPERATION));
return GL_TRUE;
}
GLboolean result;
- Error error = fenceObject->testFence(&result);
+ Error error = fenceObject->test(&result);
if (error.isError())
{
context->recordError(error);
@@ -613,7 +653,8 @@ void GL_APIENTRY TexStorage2DEXT(GLenum target, GLsizei levels, GLenum internalf
}
if (context->getClientVersion() >= 3 &&
- !ValidateES3TexStorageParameters(context, target, levels, internalformat, width, height, 1))
+ !ValidateES3TexStorage2DParameters(context, target, levels, internalformat, width,
+ height, 1))
{
return;
}
@@ -642,6 +683,21 @@ void GL_APIENTRY VertexAttribDivisorANGLE(GLuint index, GLuint divisor)
return;
}
+ if (context->getLimitations().attributeZeroRequiresZeroDivisorInEXT)
+ {
+ if (index == 0 && divisor != 0)
+ {
+ const char *errorMessage = "The current context doesn't support setting a non-zero divisor on the attribute with index zero. "
+ "Please reorder the attributes in your vertex shader so that attribute zero can have a zero divisor.";
+ context->recordError(Error(GL_INVALID_OPERATION, errorMessage));
+
+ // We also output an error message to the debugger window if tracing is active, so that developers can see the error message.
+ ERR("%s", errorMessage);
+
+ return;
+ }
+ }
+
context->setVertexAttribDivisor(index, divisor);
}
}
@@ -657,32 +713,32 @@ void GL_APIENTRY BlitFramebufferANGLE(GLint srcX0, GLint srcY0, GLint srcX1, GLi
Context *context = GetValidGlobalContext();
if (context)
{
- if (!ValidateBlitFramebufferParameters(context, srcX0, srcY0, srcX1, srcY1,
- dstX0, dstY0, dstX1, dstY1, mask, filter,
-#ifndef ANGLE_ENABLE_WINDOWS_STORE
- true))
-#else
- false))
-#endif
+ if (!context->skipValidation() &&
+ !ValidateBlitFramebufferANGLE(context, srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1,
+ dstY1, mask, filter))
{
return;
}
- Framebuffer *readFramebuffer = context->getState().getReadFramebuffer();
- ASSERT(readFramebuffer);
-
- Framebuffer *drawFramebuffer = context->getState().getDrawFramebuffer();
- ASSERT(drawFramebuffer);
+ context->blitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask,
+ filter);
+ }
+}
- Rectangle srcArea(srcX0, srcY0, srcX1 - srcX0, srcY1 - srcY0);
- Rectangle dstArea(dstX0, dstY0, dstX1 - dstX0, dstY1 - dstY0);
+void GL_APIENTRY DiscardFramebufferEXT(GLenum target, GLsizei numAttachments, const GLenum *attachments)
+{
+ EVENT("(GLenum target = 0x%X, GLsizei numAttachments = %d, attachments = 0x%0.8p)", target, numAttachments, attachments);
- Error error = drawFramebuffer->blit(context->getState(), srcArea, dstArea, mask, filter, readFramebuffer);
- if (error.isError())
+ Context *context = GetValidGlobalContext();
+ if (context)
+ {
+ if (!context->skipValidation() &&
+ !ValidateDiscardFramebufferEXT(context, target, numAttachments, attachments))
{
- context->recordError(error);
return;
}
+
+ context->discardFramebuffer(target, numAttachments, attachments);
}
}
@@ -705,14 +761,14 @@ void GL_APIENTRY GetProgramBinaryOES(GLuint program, GLsizei bufSize, GLsizei *l
Context *context = GetValidGlobalContext();
if (context)
{
- Program *programObject = context->getProgram(program);
-
- if (!programObject || !programObject->isLinked())
+ if (!ValidateGetProgramBinaryOES(context, program, bufSize, length, binaryFormat, binary))
{
- context->recordError(Error(GL_INVALID_OPERATION));
return;
}
+ Program *programObject = context->getProgram(program);
+ ASSERT(programObject != nullptr);
+
Error error = programObject->saveBinary(binaryFormat, binary, bufSize, length);
if (error.isError())
{
@@ -730,19 +786,13 @@ void GL_APIENTRY ProgramBinaryOES(GLuint program, GLenum binaryFormat, const voi
Context *context = GetValidGlobalContext();
if (context)
{
- const std::vector<GLenum> &programBinaryFormats = context->getCaps().programBinaryFormats;
- if (std::find(programBinaryFormats.begin(), programBinaryFormats.end(), binaryFormat) == programBinaryFormats.end())
+ if (!ValidateProgramBinaryOES(context, program, binaryFormat, binary, length))
{
- context->recordError(Error(GL_INVALID_ENUM));
return;
}
Program *programObject = context->getProgram(program);
- if (!programObject)
- {
- context->recordError(Error(GL_INVALID_OPERATION));
- return;
- }
+ ASSERT(programObject != nullptr);
Error error = programObject->loadBinary(binaryFormat, binary, length);
if (error.isError())
@@ -760,45 +810,12 @@ void GL_APIENTRY DrawBuffersEXT(GLsizei n, const GLenum *bufs)
Context *context = GetValidGlobalContext();
if (context)
{
- if (n < 0 || static_cast<GLuint>(n) > context->getCaps().maxDrawBuffers)
+ if (!context->skipValidation() && !ValidateDrawBuffersEXT(context, n, bufs))
{
- context->recordError(Error(GL_INVALID_VALUE));
return;
}
- ASSERT(context->getState().getDrawFramebuffer());
-
- if (context->getState().getDrawFramebuffer()->id() == 0)
- {
- if (n != 1)
- {
- context->recordError(Error(GL_INVALID_OPERATION));
- return;
- }
-
- if (bufs[0] != GL_NONE && bufs[0] != GL_BACK)
- {
- context->recordError(Error(GL_INVALID_OPERATION));
- return;
- }
- }
- else
- {
- for (int colorAttachment = 0; colorAttachment < n; colorAttachment++)
- {
- const GLenum attachment = GL_COLOR_ATTACHMENT0_EXT + colorAttachment;
- if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != attachment)
- {
- context->recordError(Error(GL_INVALID_OPERATION));
- return;
- }
- }
- }
-
- Framebuffer *framebuffer = context->getState().getDrawFramebuffer();
- ASSERT(framebuffer);
-
- framebuffer->setDrawBuffers(n, bufs);
+ context->drawBuffers(n, bufs);
}
}
@@ -867,7 +884,7 @@ void *GL_APIENTRY MapBufferOES(GLenum target, GLenum access)
return NULL;
}
- Error error = buffer->mapRange(0, buffer->getSize(), GL_MAP_WRITE_BIT);
+ Error error = buffer->map(access);
if (error.isError())
{
context->recordError(error);
@@ -901,16 +918,15 @@ GLboolean GL_APIENTRY UnmapBufferOES(GLenum target)
return GL_FALSE;
}
- // TODO: detect if we had corruption. if so, throw an error and return false.
-
- Error error = buffer->unmap();
+ GLboolean result;
+ Error error = buffer->unmap(&result);
if (error.isError())
{
context->recordError(error);
return GL_FALSE;
}
- return GL_TRUE;
+ return result;
}
return GL_FALSE;
@@ -1059,4 +1075,464 @@ void GL_APIENTRY FlushMappedBufferRangeEXT(GLenum target, GLintptr offset, GLsiz
}
}
+void GL_APIENTRY InsertEventMarkerEXT(GLsizei length, const char *marker)
+{
+ // Don't run an EVENT() macro on the EXT_debug_marker entry points.
+ // It can interfere with the debug events being set by the caller.
+
+ Context *context = GetValidGlobalContext();
+ if (context)
+ {
+ if (!context->getExtensions().debugMarker)
+ {
+ // The debug marker calls should not set error state
+ // However, it seems reasonable to set an error state if the extension is not enabled
+ context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled"));
+ return;
+ }
+
+ if (!ValidateInsertEventMarkerEXT(context, length, marker))
+ {
+ return;
+ }
+
+ context->insertEventMarker(length, marker);
+ }
+}
+
+void GL_APIENTRY PushGroupMarkerEXT(GLsizei length, const char *marker)
+{
+ // Don't run an EVENT() macro on the EXT_debug_marker entry points.
+ // It can interfere with the debug events being set by the caller.
+
+ Context *context = GetValidGlobalContext();
+ if (context)
+ {
+ if (!context->getExtensions().debugMarker)
+ {
+ // The debug marker calls should not set error state
+ // However, it seems reasonable to set an error state if the extension is not enabled
+ context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled"));
+ return;
+ }
+
+ if (!ValidatePushGroupMarkerEXT(context, length, marker))
+ {
+ return;
+ }
+
+ if (marker == nullptr)
+ {
+ // From the EXT_debug_marker spec,
+ // "If <marker> is null then an empty string is pushed on the stack."
+ context->pushGroupMarker(length, "");
+ }
+ else
+ {
+ context->pushGroupMarker(length, marker);
+ }
+ }
+}
+
+void GL_APIENTRY PopGroupMarkerEXT()
+{
+ // Don't run an EVENT() macro on the EXT_debug_marker entry points.
+ // It can interfere with the debug events being set by the caller.
+
+ Context *context = GetValidGlobalContext();
+ if (context)
+ {
+ if (!context->getExtensions().debugMarker)
+ {
+ // The debug marker calls should not set error state
+ // However, it seems reasonable to set an error state if the extension is not enabled
+ context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled"));
+ return;
+ }
+
+ context->popGroupMarker();
+ }
+}
+
+ANGLE_EXPORT void GL_APIENTRY EGLImageTargetTexture2DOES(GLenum target, GLeglImageOES image)
+{
+ EVENT("(GLenum target = 0x%X, GLeglImageOES image = 0x%0.8p)", target, image);
+
+ Context *context = GetValidGlobalContext();
+ if (context)
+ {
+ egl::Display *display = egl::GetGlobalDisplay();
+ egl::Image *imageObject = reinterpret_cast<egl::Image *>(image);
+ if (!ValidateEGLImageTargetTexture2DOES(context, display, target, imageObject))
+ {
+ return;
+ }
+
+ Texture *texture = context->getTargetTexture(target);
+ Error error = texture->setEGLImageTarget(target, imageObject);
+ if (error.isError())
+ {
+ context->recordError(error);
+ return;
+ }
+ }
+}
+
+ANGLE_EXPORT void GL_APIENTRY EGLImageTargetRenderbufferStorageOES(GLenum target,
+ GLeglImageOES image)
+{
+ EVENT("(GLenum target = 0x%X, GLeglImageOES image = 0x%0.8p)", target, image);
+
+ Context *context = GetValidGlobalContext();
+ if (context)
+ {
+ egl::Display *display = egl::GetGlobalDisplay();
+ egl::Image *imageObject = reinterpret_cast<egl::Image *>(image);
+ if (!ValidateEGLImageTargetRenderbufferStorageOES(context, display, target, imageObject))
+ {
+ return;
+ }
+
+ Renderbuffer *renderbuffer = context->getState().getCurrentRenderbuffer();
+ Error error = renderbuffer->setStorageEGLImageTarget(imageObject);
+ if (error.isError())
+ {
+ context->recordError(error);
+ return;
+ }
+ }
+}
+
+void GL_APIENTRY BindVertexArrayOES(GLuint array)
+{
+ EVENT("(GLuint array = %u)", array);
+
+ Context *context = GetValidGlobalContext();
+ if (context)
+ {
+ if (!ValidateBindVertexArrayOES(context, array))
+ {
+ return;
+ }
+
+ context->bindVertexArray(array);
+ }
+}
+
+void GL_APIENTRY DeleteVertexArraysOES(GLsizei n, const GLuint *arrays)
+{
+ EVENT("(GLsizei n = %d, const GLuint* arrays = 0x%0.8p)", n, arrays);
+
+ Context *context = GetValidGlobalContext();
+ if (context)
+ {
+ if (!ValidateDeleteVertexArraysOES(context, n))
+ {
+ return;
+ }
+
+ for (int arrayIndex = 0; arrayIndex < n; arrayIndex++)
+ {
+ if (arrays[arrayIndex] != 0)
+ {
+ context->deleteVertexArray(arrays[arrayIndex]);
+ }
+ }
+ }
+}
+
+void GL_APIENTRY GenVertexArraysOES(GLsizei n, GLuint *arrays)
+{
+ EVENT("(GLsizei n = %d, GLuint* arrays = 0x%0.8p)", n, arrays);
+
+ Context *context = GetValidGlobalContext();
+ if (context)
+ {
+ if (!ValidateGenVertexArraysOES(context, n))
+ {
+ return;
+ }
+
+ for (int arrayIndex = 0; arrayIndex < n; arrayIndex++)
+ {
+ arrays[arrayIndex] = context->createVertexArray();
+ }
+ }
+}
+
+GLboolean GL_APIENTRY IsVertexArrayOES(GLuint array)
+{
+ EVENT("(GLuint array = %u)", array);
+
+ Context *context = GetValidGlobalContext();
+ if (context)
+ {
+ if (!ValidateIsVertexArrayOES(context))
+ {
+ return GL_FALSE;
+ }
+
+ if (array == 0)
+ {
+ return GL_FALSE;
+ }
+
+ VertexArray *vao = context->getVertexArray(array);
+
+ return (vao != nullptr ? GL_TRUE : GL_FALSE);
+ }
+
+ return GL_FALSE;
+}
+
+void GL_APIENTRY DebugMessageControlKHR(GLenum source,
+ GLenum type,
+ GLenum severity,
+ GLsizei count,
+ const GLuint *ids,
+ GLboolean enabled)
+{
+ EVENT(
+ "(GLenum source = 0x%X, GLenum type = 0x%X, GLenum severity = 0x%X, GLsizei count = %d, "
+ "GLint *ids = 0x%0.8p, GLboolean enabled = %d)",
+ source, type, severity, count, ids, enabled);
+
+ Context *context = GetValidGlobalContext();
+ if (context)
+ {
+ if (!ValidateDebugMessageControlKHR(context, source, type, severity, count, ids, enabled))
+ {
+ return;
+ }
+
+ std::vector<GLuint> idVector(ids, ids + count);
+ context->getState().getDebug().setMessageControl(
+ source, type, severity, std::move(idVector), (enabled != GL_FALSE));
+ }
+}
+
+void GL_APIENTRY DebugMessageInsertKHR(GLenum source,
+ GLenum type,
+ GLuint id,
+ GLenum severity,
+ GLsizei length,
+ const GLchar *buf)
+{
+ EVENT(
+ "(GLenum source = 0x%X, GLenum type = 0x%X, GLint id = %d, GLenum severity = 0x%X, GLsizei "
+ "length = %d, const GLchar *buf = 0x%0.8p)",
+ source, type, id, severity, length, buf);
+
+ Context *context = GetValidGlobalContext();
+ if (context)
+ {
+ if (!ValidateDebugMessageInsertKHR(context, source, type, id, severity, length, buf))
+ {
+ return;
+ }
+
+ std::string msg(buf, (length > 0) ? static_cast<size_t>(length) : strlen(buf));
+ context->getState().getDebug().insertMessage(source, type, id, severity, std::move(msg));
+ }
+}
+
+void GL_APIENTRY DebugMessageCallbackKHR(GLDEBUGPROCKHR callback, const void *userParam)
+{
+ EVENT("(GLDEBUGPROCKHR callback = 0x%0.8p, const void *userParam = 0x%0.8p)", callback,
+ userParam);
+
+ Context *context = GetValidGlobalContext();
+ if (context)
+ {
+ if (!ValidateDebugMessageCallbackKHR(context, callback, userParam))
+ {
+ return;
+ }
+
+ context->getState().getDebug().setCallback(callback, userParam);
+ }
+}
+
+GLuint GL_APIENTRY GetDebugMessageLogKHR(GLuint count,
+ GLsizei bufSize,
+ GLenum *sources,
+ GLenum *types,
+ GLuint *ids,
+ GLenum *severities,
+ GLsizei *lengths,
+ GLchar *messageLog)
+{
+ EVENT(
+ "(GLsizei count = %d, GLsizei bufSize = %d, GLenum *sources, GLenum *types = 0x%0.8p, "
+ "GLuint *ids = 0x%0.8p, GLenum *severities = 0x%0.8p, GLsizei *lengths = 0x%0.8p, GLchar "
+ "*messageLog = 0x%0.8p)",
+ count, bufSize, sources, types, ids, severities, lengths, messageLog);
+
+ Context *context = GetValidGlobalContext();
+ if (context)
+ {
+ if (!ValidateGetDebugMessageLogKHR(context, count, bufSize, sources, types, ids, severities,
+ lengths, messageLog))
+ {
+ return 0;
+ }
+
+ return static_cast<GLuint>(context->getState().getDebug().getMessages(
+ count, bufSize, sources, types, ids, severities, lengths, messageLog));
+ }
+
+ return 0;
+}
+
+void GL_APIENTRY PushDebugGroupKHR(GLenum source, GLuint id, GLsizei length, const GLchar *message)
+{
+ EVENT(
+ "(GLenum source = 0x%X, GLuint id = 0x%X, GLsizei length = %d, const GLchar *message = "
+ "0x%0.8p)",
+ source, id, length, message);
+
+ Context *context = GetValidGlobalContext();
+ if (context)
+ {
+ if (!ValidatePushDebugGroupKHR(context, source, id, length, message))
+ {
+ return;
+ }
+
+ std::string msg(message, (length > 0) ? static_cast<size_t>(length) : strlen(message));
+ context->getState().getDebug().pushGroup(source, id, std::move(msg));
+ }
+}
+
+void GL_APIENTRY PopDebugGroupKHR(void)
+{
+ EVENT("()");
+
+ Context *context = GetValidGlobalContext();
+ if (context)
+ {
+ if (!ValidatePopDebugGroupKHR(context))
+ {
+ return;
+ }
+
+ context->getState().getDebug().popGroup();
+ }
+}
+
+void GL_APIENTRY ObjectLabelKHR(GLenum identifier, GLuint name, GLsizei length, const GLchar *label)
+{
+ EVENT(
+ "(GLenum identifier = 0x%X, GLuint name = %u, GLsizei length = %d, const GLchar *label = "
+ "0x%0.8p)",
+ identifier, name, length, label);
+
+ Context *context = GetValidGlobalContext();
+ if (context)
+ {
+ if (!ValidateObjectLabelKHR(context, identifier, name, length, label))
+ {
+ return;
+ }
+
+ LabeledObject *object = context->getLabeledObject(identifier, name);
+ ASSERT(object != nullptr);
+
+ std::string lbl(label, (length > 0) ? static_cast<size_t>(length) : strlen(label));
+ object->setLabel(lbl);
+ }
+}
+
+void GL_APIENTRY
+GetObjectLabelKHR(GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label)
+{
+ EVENT(
+ "(GLenum identifier = 0x%X, GLuint name = %u, GLsizei bufSize = %d, GLsizei *length = "
+ "0x%0.8p, GLchar *label = 0x%0.8p)",
+ identifier, name, bufSize, length, label);
+
+ Context *context = GetValidGlobalContext();
+ if (context)
+ {
+ if (!ValidateGetObjectLabelKHR(context, identifier, name, bufSize, length, label))
+ {
+ return;
+ }
+
+ LabeledObject *object = context->getLabeledObject(identifier, name);
+ ASSERT(object != nullptr);
+
+ const std::string &objectLabel = object->getLabel();
+ size_t writeLength = std::min(static_cast<size_t>(bufSize) - 1, objectLabel.length());
+ std::copy(objectLabel.begin(), objectLabel.begin() + writeLength, label);
+ label[writeLength] = '\0';
+ *length = static_cast<GLsizei>(writeLength);
+ }
+}
+
+void GL_APIENTRY ObjectPtrLabelKHR(const void *ptr, GLsizei length, const GLchar *label)
+{
+ EVENT("(const void *ptr = 0x%0.8p, GLsizei length = %d, const GLchar *label = 0x%0.8p)", ptr,
+ length, label);
+
+ Context *context = GetValidGlobalContext();
+ if (context)
+ {
+ if (!ValidateObjectPtrLabelKHR(context, ptr, length, label))
+ {
+ return;
+ }
+
+ LabeledObject *object = context->getLabeledObjectFromPtr(ptr);
+ ASSERT(object != nullptr);
+
+ std::string lbl(label, (length > 0) ? static_cast<size_t>(length) : strlen(label));
+ object->setLabel(lbl);
+ }
+}
+
+void GL_APIENTRY GetObjectPtrLabelKHR(const void *ptr,
+ GLsizei bufSize,
+ GLsizei *length,
+ GLchar *label)
+{
+ EVENT(
+ "(const void *ptr = 0x%0.8p, GLsizei bufSize = %d, GLsizei *length = 0x%0.8p, GLchar "
+ "*label = 0x%0.8p)",
+ ptr, bufSize, length, label);
+
+ Context *context = GetValidGlobalContext();
+ if (context)
+ {
+ if (!ValidateGetObjectPtrLabelKHR(context, ptr, bufSize, length, label))
+ {
+ return;
+ }
+
+ LabeledObject *object = context->getLabeledObjectFromPtr(ptr);
+ ASSERT(object != nullptr);
+
+ const std::string &objectLabel = object->getLabel();
+ size_t writeLength = std::min(static_cast<size_t>(bufSize) - 1, objectLabel.length());
+ std::copy(objectLabel.begin(), objectLabel.begin() + writeLength, label);
+ label[writeLength] = '\0';
+ *length = static_cast<GLsizei>(writeLength);
+ }
+}
+
+void GL_APIENTRY GetPointervKHR(GLenum pname, void **params)
+{
+ EVENT("(GLenum pname = 0x%X, void **params = 0x%0.8p)", pname, params);
+
+ Context *context = GetValidGlobalContext();
+ if (context)
+ {
+ if (!ValidateGetPointervKHR(context, pname, params))
+ {
+ return;
+ }
+
+ context->getPointerv(pname, params);
+ }
+}
}
diff --git a/src/3rdparty/angle/src/libGLESv2/entry_points_gles_2_0_ext.h b/src/3rdparty/angle/src/libGLESv2/entry_points_gles_2_0_ext.h
index 816519fe1f..a2fb9c5e80 100644
--- a/src/3rdparty/angle/src/libGLESv2/entry_points_gles_2_0_ext.h
+++ b/src/3rdparty/angle/src/libGLESv2/entry_points_gles_2_0_ext.h
@@ -22,6 +22,9 @@ ANGLE_EXPORT void GL_APIENTRY BlitFramebufferANGLE(GLint srcX0, GLint srcY0, GLi
// GL_ANGLE_framebuffer_multisample
ANGLE_EXPORT void GL_APIENTRY RenderbufferStorageMultisampleANGLE(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+// GL_EXT_discard_framebuffer
+ANGLE_EXPORT void GL_APIENTRY DiscardFramebufferEXT(GLenum target, GLsizei numAttachments, const GLenum *attachments);
+
// GL_NV_fence
ANGLE_EXPORT void GL_APIENTRY DeleteFencesNV(GLsizei n, const GLuint* fences);
ANGLE_EXPORT void GL_APIENTRY GenFencesNV(GLsizei n, GLuint* fences);
@@ -52,6 +55,12 @@ ANGLE_EXPORT void GL_APIENTRY EndQueryEXT(GLenum target);
ANGLE_EXPORT void GL_APIENTRY GetQueryivEXT(GLenum target, GLenum pname, GLint *params);
ANGLE_EXPORT void GL_APIENTRY GetQueryObjectuivEXT(GLuint id, GLenum pname, GLuint *params);
+// GL_EXT_disjoint_timer_query
+ANGLE_EXPORT void GL_APIENTRY QueryCounterEXT(GLuint id, GLenum target);
+ANGLE_EXPORT void GL_APIENTRY GetQueryObjectivEXT(GLuint id, GLenum pname, GLint *params);
+ANGLE_EXPORT void GL_APIENTRY GetQueryObjecti64vEXT(GLuint id, GLenum pname, GLint64 *params);
+ANGLE_EXPORT void GL_APIENTRY GetQueryObjectui64vEXT(GLuint id, GLenum pname, GLuint64 *params);
+
// GL_EXT_draw_buffers
ANGLE_EXPORT void GL_APIENTRY DrawBuffersEXT(GLsizei n, const GLenum *bufs);
@@ -73,6 +82,64 @@ ANGLE_EXPORT void GL_APIENTRY GetBufferPointervOES(GLenum target, GLenum pname,
ANGLE_EXPORT void *GL_APIENTRY MapBufferRangeEXT(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access);
ANGLE_EXPORT void GL_APIENTRY FlushMappedBufferRangeEXT(GLenum target, GLintptr offset, GLsizeiptr length);
+// GL_EXT_debug_marker
+ANGLE_EXPORT void GL_APIENTRY InsertEventMarkerEXT(GLsizei length, const char *marker);
+ANGLE_EXPORT void GL_APIENTRY PushGroupMarkerEXT(GLsizei length, const char *marker);
+ANGLE_EXPORT void GL_APIENTRY PopGroupMarkerEXT();
+
+// GL_OES_EGL_image
+ANGLE_EXPORT void GL_APIENTRY EGLImageTargetTexture2DOES(GLenum target, GLeglImageOES image);
+ANGLE_EXPORT void GL_APIENTRY EGLImageTargetRenderbufferStorageOES(GLenum target,
+ GLeglImageOES image);
+
+// GL_OES_vertex_array_object
+ANGLE_EXPORT void GL_APIENTRY BindVertexArrayOES(GLuint array);
+ANGLE_EXPORT void GL_APIENTRY DeleteVertexArraysOES(GLsizei n, const GLuint *arrays);
+ANGLE_EXPORT void GL_APIENTRY GenVertexArraysOES(GLsizei n, GLuint *arrays);
+ANGLE_EXPORT GLboolean GL_APIENTRY IsVertexArrayOES(GLuint array);
+
+// GL_KHR_debug
+ANGLE_EXPORT void GL_APIENTRY DebugMessageControlKHR(GLenum source,
+ GLenum type,
+ GLenum severity,
+ GLsizei count,
+ const GLuint *ids,
+ GLboolean enabled);
+ANGLE_EXPORT void GL_APIENTRY DebugMessageInsertKHR(GLenum source,
+ GLenum type,
+ GLuint id,
+ GLenum severity,
+ GLsizei length,
+ const GLchar *buf);
+ANGLE_EXPORT void GL_APIENTRY DebugMessageCallbackKHR(GLDEBUGPROCKHR callback,
+ const void *userParam);
+ANGLE_EXPORT GLuint GL_APIENTRY GetDebugMessageLogKHR(GLuint count,
+ GLsizei bufSize,
+ GLenum *sources,
+ GLenum *types,
+ GLuint *ids,
+ GLenum *severities,
+ GLsizei *lengths,
+ GLchar *messageLog);
+ANGLE_EXPORT void GL_APIENTRY PushDebugGroupKHR(GLenum source,
+ GLuint id,
+ GLsizei length,
+ const GLchar *message);
+ANGLE_EXPORT void GL_APIENTRY PopDebugGroupKHR(void);
+ANGLE_EXPORT void GL_APIENTRY ObjectLabelKHR(GLenum identifier,
+ GLuint name,
+ GLsizei length,
+ const GLchar *label);
+ANGLE_EXPORT void GL_APIENTRY
+GetObjectLabelKHR(GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label);
+ANGLE_EXPORT void GL_APIENTRY ObjectPtrLabelKHR(const void *ptr,
+ GLsizei length,
+ const GLchar *label);
+ANGLE_EXPORT void GL_APIENTRY GetObjectPtrLabelKHR(const void *ptr,
+ GLsizei bufSize,
+ GLsizei *length,
+ GLchar *label);
+ANGLE_EXPORT void GL_APIENTRY GetPointervKHR(GLenum pname, void **params);
}
#endif // LIBGLESV2_ENTRYPOINTGLES20EXT_H_
diff --git a/src/3rdparty/angle/src/libGLESv2/entry_points_gles_3_0.cpp b/src/3rdparty/angle/src/libGLESv2/entry_points_gles_3_0.cpp
index d8bdcd2e50..856129aa07 100644
--- a/src/3rdparty/angle/src/libGLESv2/entry_points_gles_3_0.cpp
+++ b/src/3rdparty/angle/src/libGLESv2/entry_points_gles_3_0.cpp
@@ -35,13 +35,12 @@ void GL_APIENTRY ReadBuffer(GLenum mode)
Context *context = GetValidGlobalContext();
if (context)
{
- if (!ValidateReadBuffer(context, mode))
+ if (!context->skipValidation() && !ValidateReadBuffer(context, mode))
{
return;
}
- Framebuffer *readFBO = context->getState().getReadFramebuffer();
- readFBO->setReadBuffer(mode);
+ context->readBuffer(mode);
}
}
@@ -59,7 +58,7 @@ void GL_APIENTRY DrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsize
return;
}
- rx::RangeUI indexRange;
+ IndexRange indexRange;
if (!ValidateDrawElements(context, mode, count, type, indices, 0, &indexRange))
{
return;
@@ -75,7 +74,8 @@ void GL_APIENTRY DrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsize
// a drawRangeElements call - the GL back-end is free to choose to call drawRangeElements based on the
// validated index range. If index validation is removed, adding drawRangeElements to the context interface
// should be reconsidered.
- Error error = context->drawElements(mode, count, type, indices, 0, indexRange);
+ Error error =
+ context->drawRangeElements(mode, start, end, count, type, indices, indexRange);
if (error.isError())
{
context->recordError(error);
@@ -101,15 +101,16 @@ void GL_APIENTRY TexImage3D(GLenum target, GLint level, GLint internalformat, GL
}
// validateES3TexImageFormat sets the error code if there is an error
- if (!ValidateES3TexImageParameters(context, target, level, internalformat, false, false,
- 0, 0, 0, width, height, depth, border, format, type, pixels))
+ if (!ValidateES3TexImage3DParameters(context, target, level, internalformat, false, false,
+ 0, 0, 0, width, height, depth, border, format, type,
+ pixels))
{
return;
}
Extents size(width, height, depth);
Texture *texture = context->getTargetTexture(target);
- Error error = texture->setImage(target, level, internalformat, size, format, type, context->getState().getUnpackState(),
+ Error error = texture->setImage(context, target, level, internalformat, size, format, type,
reinterpret_cast<const uint8_t *>(pixels));
if (error.isError())
{
@@ -136,9 +137,9 @@ void GL_APIENTRY TexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint
}
// validateES3TexImageFormat sets the error code if there is an error
- if (!ValidateES3TexImageParameters(context, target, level, GL_NONE, false, true,
- xoffset, yoffset, zoffset, width, height, depth, 0,
- format, type, pixels))
+ if (!ValidateES3TexImage3DParameters(context, target, level, GL_NONE, false, true, xoffset,
+ yoffset, zoffset, width, height, depth, 0, format,
+ type, pixels))
{
return;
}
@@ -151,7 +152,7 @@ void GL_APIENTRY TexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint
Box area(xoffset, yoffset, zoffset, width, height, depth);
Texture *texture = context->getTargetTexture(target);
- Error error = texture->setSubImage(target, level, area, format, type, context->getState().getUnpackState(),
+ Error error = texture->setSubImage(context, target, level, area, format, type,
reinterpret_cast<const uint8_t *>(pixels));
if (error.isError())
{
@@ -170,29 +171,14 @@ void GL_APIENTRY CopyTexSubImage3D(GLenum target, GLint level, GLint xoffset, GL
Context *context = GetValidGlobalContext();
if (context)
{
- if (context->getClientVersion() < 3)
- {
- context->recordError(Error(GL_INVALID_OPERATION));
- return;
- }
-
- if (!ValidateES3CopyTexImageParameters(context, target, level, GL_NONE, true, xoffset, yoffset, zoffset,
- x, y, width, height, 0))
+ if (!context->skipValidation() &&
+ !ValidateCopyTexSubImage3D(context, target, level, xoffset, yoffset, zoffset, x, y,
+ width, height))
{
return;
}
- Offset destOffset(xoffset, yoffset, zoffset);
- Rectangle sourceArea(x, y, width, height);
-
- const Framebuffer *framebuffer = context->getState().getReadFramebuffer();
- Texture *texture = context->getTargetTexture(target);
- Error error = texture->copySubImage(target, level, destOffset, sourceArea, framebuffer);
- if (error.isError())
- {
- context->recordError(error);
- return;
- }
+ context->copyTexSubImage3D(target, level, xoffset, yoffset, zoffset, x, y, width, height);
}
}
@@ -206,30 +192,17 @@ void GL_APIENTRY CompressedTexImage3D(GLenum target, GLint level, GLenum interna
Context *context = GetValidGlobalContext();
if (context)
{
- if (context->getClientVersion() < 3)
- {
- context->recordError(Error(GL_INVALID_OPERATION));
- return;
- }
-
- const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat);
- if (imageSize < 0 || static_cast<GLuint>(imageSize) != formatInfo.computeBlockSize(GL_UNSIGNED_BYTE, width, height))
- {
- context->recordError(Error(GL_INVALID_VALUE));
- return;
- }
-
- // validateES3TexImageFormat sets the error code if there is an error
- if (!ValidateES3TexImageParameters(context, target, level, internalformat, true, false,
- 0, 0, 0, width, height, depth, border, GL_NONE, GL_NONE, data))
+ if (!ValidateCompressedTexImage3D(context, target, level, internalformat, width, height,
+ depth, border, imageSize, data))
{
return;
}
Extents size(width, height, depth);
Texture *texture = context->getTargetTexture(target);
- Error error = texture->setCompressedImage(target, level, internalformat, size, context->getState().getUnpackState(),
- reinterpret_cast<const uint8_t *>(data));
+ Error error =
+ texture->setCompressedImage(context, target, level, internalformat, size, imageSize,
+ reinterpret_cast<const uint8_t *>(data));
if (error.isError())
{
context->recordError(error);
@@ -268,8 +241,8 @@ void GL_APIENTRY CompressedTexSubImage3D(GLenum target, GLint level, GLint xoffs
}
// validateES3TexImageFormat sets the error code if there is an error
- if (!ValidateES3TexImageParameters(context, target, level, GL_NONE, true, true,
- 0, 0, 0, width, height, depth, 0, GL_NONE, GL_NONE, data))
+ if (!ValidateES3TexImage3DParameters(context, target, level, GL_NONE, true, true, 0, 0, 0,
+ width, height, depth, 0, GL_NONE, GL_NONE, data))
{
return;
}
@@ -282,8 +255,9 @@ void GL_APIENTRY CompressedTexSubImage3D(GLenum target, GLint level, GLint xoffs
Box area(xoffset, yoffset, zoffset, width, height, depth);
Texture *texture = context->getTargetTexture(target);
- Error error = texture->setCompressedSubImage(target, level, area, format, context->getState().getUnpackState(),
- reinterpret_cast<const uint8_t *>(data));
+ Error error =
+ texture->setCompressedSubImage(context, target, level, area, format, imageSize,
+ reinterpret_cast<const uint8_t *>(data));
if (error.isError())
{
context->recordError(error);
@@ -299,15 +273,8 @@ void GL_APIENTRY GenQueries(GLsizei n, GLuint* ids)
Context *context = GetValidGlobalContext();
if (context)
{
- if (context->getClientVersion() < 3)
- {
- context->recordError(Error(GL_INVALID_OPERATION));
- return;
- }
-
- if (n < 0)
+ if (!ValidateGenQueries(context, n, ids))
{
- context->recordError(Error(GL_INVALID_VALUE));
return;
}
@@ -325,19 +292,12 @@ void GL_APIENTRY DeleteQueries(GLsizei n, const GLuint* ids)
Context *context = GetValidGlobalContext();
if (context)
{
- if (context->getClientVersion() < 3)
+ if (!ValidateDeleteQueries(context, n, ids))
{
- context->recordError(Error(GL_INVALID_OPERATION));
return;
}
- if (n < 0)
- {
- context->recordError(Error(GL_INVALID_VALUE));
- return;
- }
-
- for (GLsizei i = 0; i < n; i++)
+ for (int i = 0; i < n; i++)
{
context->deleteQuery(ids[i]);
}
@@ -370,12 +330,6 @@ void GL_APIENTRY BeginQuery(GLenum target, GLuint id)
Context *context = GetValidGlobalContext();
if (context)
{
- if (context->getClientVersion() < 3)
- {
- context->recordError(Error(GL_INVALID_OPERATION));
- return;
- }
-
if (!ValidateBeginQuery(context, target, id))
{
return;
@@ -397,12 +351,6 @@ void GL_APIENTRY EndQuery(GLenum target)
Context *context = GetValidGlobalContext();
if (context)
{
- if (context->getClientVersion() < 3)
- {
- context->recordError(Error(GL_INVALID_OPERATION));
- return;
- }
-
if (!ValidateEndQuery(context, target))
{
return;
@@ -424,28 +372,12 @@ void GL_APIENTRY GetQueryiv(GLenum target, GLenum pname, GLint* params)
Context *context = GetValidGlobalContext();
if (context)
{
- if (context->getClientVersion() < 3)
+ if (!ValidateGetQueryiv(context, target, pname, params))
{
- context->recordError(Error(GL_INVALID_OPERATION));
return;
}
- if (!ValidQueryType(context, target))
- {
- context->recordError(Error(GL_INVALID_ENUM));
- return;
- }
-
- switch (pname)
- {
- case GL_CURRENT_QUERY:
- params[0] = static_cast<GLint>(context->getState().getActiveQueryId(target));
- break;
-
- default:
- context->recordError(Error(GL_INVALID_ENUM));
- return;
- }
+ context->getQueryiv(target, pname, params);
}
}
@@ -456,52 +388,15 @@ void GL_APIENTRY GetQueryObjectuiv(GLuint id, GLenum pname, GLuint* params)
Context *context = GetValidGlobalContext();
if (context)
{
- if (context->getClientVersion() < 3)
+ if (!ValidateGetQueryObjectuiv(context, id, pname, params))
{
- context->recordError(Error(GL_INVALID_OPERATION));
- return;
- }
-
- Query *queryObject = context->getQuery(id, false, GL_NONE);
-
- if (!queryObject)
- {
- context->recordError(Error(GL_INVALID_OPERATION));
- return;
- }
-
- if (context->getState().getActiveQueryId(queryObject->getType()) == id)
- {
- context->recordError(Error(GL_INVALID_OPERATION));
return;
}
- switch(pname)
+ Error error = context->getQueryObjectuiv(id, pname, params);
+ if (error.isError())
{
- case GL_QUERY_RESULT_EXT:
- {
- Error error = queryObject->getResult(params);
- if (error.isError())
- {
- context->recordError(error);
- return;
- }
- }
- break;
-
- case GL_QUERY_RESULT_AVAILABLE_EXT:
- {
- Error error = queryObject->isResultAvailable(params);
- if (error.isError())
- {
- context->recordError(error);
- return;
- }
- }
- break;
-
- default:
- context->recordError(Error(GL_INVALID_ENUM));
+ context->recordError(error);
return;
}
}
@@ -548,13 +443,12 @@ void GL_APIENTRY DrawBuffers(GLsizei n, const GLenum* bufs)
Context *context = GetValidGlobalContext();
if (context)
{
- if (context->getClientVersion() < 3)
+ if (!context->skipValidation() && !ValidateDrawBuffers(context, n, bufs))
{
- context->recordError(Error(GL_INVALID_OPERATION));
return;
}
- DrawBuffersEXT(n, bufs);
+ context->drawBuffers(n, bufs);
}
}
@@ -675,34 +569,15 @@ void GL_APIENTRY BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint sr
Context *context = GetValidGlobalContext();
if (context)
{
- if (context->getClientVersion() < 3)
+ if (!context->skipValidation() &&
+ !ValidateBlitFramebuffer(context, srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1,
+ dstY1, mask, filter))
{
- context->recordError(Error(GL_INVALID_OPERATION));
return;
}
- if (!ValidateBlitFramebufferParameters(context, srcX0, srcY0, srcX1, srcY1,
- dstX0, dstY0, dstX1, dstY1, mask, filter,
- false))
- {
- return;
- }
-
- Framebuffer *readFramebuffer = context->getState().getReadFramebuffer();
- ASSERT(readFramebuffer);
-
- Framebuffer *drawFramebuffer = context->getState().getDrawFramebuffer();
- ASSERT(drawFramebuffer);
-
- Rectangle srcArea(srcX0, srcY0, srcX1 - srcX0, srcY1 - srcY0);
- Rectangle dstArea(dstX0, dstY0, dstX1 - dstX0, dstY1 - dstY0);
-
- Error error = drawFramebuffer->blit(context->getState(), srcArea, dstArea, mask, filter, readFramebuffer);
- if (error.isError())
- {
- context->recordError(error);
- return;
- }
+ context->blitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask,
+ filter);
}
}
@@ -738,37 +613,13 @@ void GL_APIENTRY FramebufferTextureLayer(GLenum target, GLenum attachment, GLuin
Context *context = GetValidGlobalContext();
if (context)
{
- if (!ValidateFramebufferTextureLayer(context, target, attachment, texture,
- level, layer))
+ if (!context->skipValidation() &&
+ !ValidateFramebufferTextureLayer(context, target, attachment, texture, level, layer))
{
return;
}
- Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
- ASSERT(framebuffer);
-
- if (texture != 0)
- {
- Texture *textureObject = context->getTexture(texture);
-
- ImageIndex index = ImageIndex::MakeInvalid();
-
- if (textureObject->getTarget() == GL_TEXTURE_3D)
- {
- index = ImageIndex::Make3D(level, layer);
- }
- else
- {
- ASSERT(textureObject->getTarget() == GL_TEXTURE_2D_ARRAY);
- index = ImageIndex::Make2DArray(level, layer);
- }
-
- framebuffer->setTextureAttachment(attachment, textureObject, index);
- }
- else
- {
- framebuffer->setNULLAttachment(attachment);
- }
+ context->framebufferTextureLayer(target, attachment, texture, level, layer);
}
}
@@ -816,19 +667,8 @@ void GL_APIENTRY BindVertexArray(GLuint array)
Context *context = GetValidGlobalContext();
if (context)
{
- if (context->getClientVersion() < 3)
- {
- context->recordError(Error(GL_INVALID_OPERATION));
- return;
- }
-
- VertexArray *vao = context->getVertexArray(array);
-
- if (!vao)
+ if (!ValidateBindVertexArray(context, array))
{
- // The default VAO should always exist
- ASSERT(array != 0);
- context->recordError(Error(GL_INVALID_OPERATION));
return;
}
@@ -843,15 +683,8 @@ void GL_APIENTRY DeleteVertexArrays(GLsizei n, const GLuint* arrays)
Context *context = GetValidGlobalContext();
if (context)
{
- if (context->getClientVersion() < 3)
- {
- context->recordError(Error(GL_INVALID_OPERATION));
- return;
- }
-
- if (n < 0)
+ if (!ValidateDeleteVertexArrays(context, n))
{
- context->recordError(Error(GL_INVALID_VALUE));
return;
}
@@ -872,15 +705,8 @@ void GL_APIENTRY GenVertexArrays(GLsizei n, GLuint* arrays)
Context *context = GetValidGlobalContext();
if (context)
{
- if (context->getClientVersion() < 3)
+ if (!ValidateGenVertexArrays(context, n))
{
- context->recordError(Error(GL_INVALID_OPERATION));
- return;
- }
-
- if (n < 0)
- {
- context->recordError(Error(GL_INVALID_VALUE));
return;
}
@@ -898,9 +724,8 @@ GLboolean GL_APIENTRY IsVertexArray(GLuint array)
Context *context = GetValidGlobalContext();
if (context)
{
- if (context->getClientVersion() < 3)
+ if (!ValidateIsVertexArray(context))
{
- context->recordError(Error(GL_INVALID_OPERATION));
return GL_FALSE;
}
@@ -1026,7 +851,7 @@ void GL_APIENTRY BeginTransformFeedback(GLenum primitiveMode)
TransformFeedback *transformFeedback = context->getState().getCurrentTransformFeedback();
ASSERT(transformFeedback != NULL);
- if (transformFeedback->isStarted())
+ if (transformFeedback->isActive())
{
context->recordError(Error(GL_INVALID_OPERATION));
return;
@@ -1038,7 +863,7 @@ void GL_APIENTRY BeginTransformFeedback(GLenum primitiveMode)
}
else
{
- transformFeedback->start(primitiveMode);
+ transformFeedback->begin(primitiveMode);
}
}
}
@@ -1059,13 +884,13 @@ void GL_APIENTRY EndTransformFeedback(void)
TransformFeedback *transformFeedback = context->getState().getCurrentTransformFeedback();
ASSERT(transformFeedback != NULL);
- if (!transformFeedback->isStarted())
+ if (!transformFeedback->isActive())
{
context->recordError(Error(GL_INVALID_OPERATION));
return;
}
- transformFeedback->stop();
+ transformFeedback->end();
}
}
@@ -1126,7 +951,7 @@ void GL_APIENTRY BindBufferRange(GLenum target, GLuint index, GLuint buffer, GLi
// Cannot bind a transform feedback buffer if the current transform feedback is active (3.0.4 pg 91 section 2.15.2)
TransformFeedback *curTransformFeedback = context->getState().getCurrentTransformFeedback();
- if (curTransformFeedback && curTransformFeedback->isStarted())
+ if (curTransformFeedback && curTransformFeedback->isActive())
{
context->recordError(Error(GL_INVALID_OPERATION));
return;
@@ -1200,7 +1025,7 @@ void GL_APIENTRY BindBufferBase(GLenum target, GLuint index, GLuint buffer)
{
// Cannot bind a transform feedback buffer if the current transform feedback is active (3.0.4 pg 91 section 2.15.2)
TransformFeedback *curTransformFeedback = context->getState().getCurrentTransformFeedback();
- if (curTransformFeedback && curTransformFeedback->isStarted())
+ if (curTransformFeedback && curTransformFeedback->isActive())
{
context->recordError(Error(GL_INVALID_OPERATION));
return;
@@ -1258,14 +1083,12 @@ void GL_APIENTRY TransformFeedbackVaryings(GLuint program, GLsizei count, const
return;
}
- if (!ValidProgram(context, program))
+ Program *programObject = GetValidProgram(context, program);
+ if (!programObject)
{
return;
}
- Program *programObject = context->getProgram(program);
- ASSERT(programObject);
-
programObject->setTransformFeedbackVaryings(count, varyings, bufferMode);
}
}
@@ -1291,14 +1114,12 @@ void GL_APIENTRY GetTransformFeedbackVarying(GLuint program, GLuint index, GLsiz
return;
}
- if (!ValidProgram(context, program))
+ Program *programObject = GetValidProgram(context, program);
+ if (!programObject)
{
return;
}
- Program *programObject = context->getProgram(program);
- ASSERT(programObject);
-
if (index >= static_cast<GLuint>(programObject->getTransformFeedbackVaryingCount()))
{
context->recordError(Error(GL_INVALID_VALUE));
@@ -1714,43 +1535,13 @@ void GL_APIENTRY ClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint* val
Context *context = GetValidGlobalContext();
if (context)
{
- if (!ValidateClearBuffer(context))
- {
- return;
- }
-
- switch (buffer)
+ if (!context->skipValidation() &&
+ !ValidateClearBufferiv(context, buffer, drawbuffer, value))
{
- case GL_COLOR:
- if (drawbuffer < 0 || static_cast<GLuint>(drawbuffer) >= context->getCaps().maxDrawBuffers)
- {
- context->recordError(Error(GL_INVALID_VALUE));
- return;
- }
- break;
-
- case GL_STENCIL:
- if (drawbuffer != 0)
- {
- context->recordError(Error(GL_INVALID_VALUE));
- return;
- }
- break;
-
- default:
- context->recordError(Error(GL_INVALID_ENUM));
return;
}
- Framebuffer *framebufferObject = context->getState().getDrawFramebuffer();
- ASSERT(framebufferObject);
-
- Error error = framebufferObject->clearBufferiv(context->getState(), buffer, drawbuffer, value);
- if (error.isError())
- {
- context->recordError(error);
- return;
- }
+ context->clearBufferiv(buffer, drawbuffer, value);
}
}
@@ -1762,35 +1553,13 @@ void GL_APIENTRY ClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint* v
Context *context = GetValidGlobalContext();
if (context)
{
- if (!ValidateClearBuffer(context))
+ if (!context->skipValidation() &&
+ !ValidateClearBufferuiv(context, buffer, drawbuffer, value))
{
return;
}
- switch (buffer)
- {
- case GL_COLOR:
- if (drawbuffer < 0 || static_cast<GLuint>(drawbuffer) >= context->getCaps().maxDrawBuffers)
- {
- context->recordError(Error(GL_INVALID_VALUE));
- return;
- }
- break;
-
- default:
- context->recordError(Error(GL_INVALID_ENUM));
- return;
- }
-
- Framebuffer *framebufferObject = context->getState().getDrawFramebuffer();
- ASSERT(framebufferObject);
-
- Error error = framebufferObject->clearBufferuiv(context->getState(), buffer, drawbuffer, value);
- if (error.isError())
- {
- context->recordError(error);
- return;
- }
+ context->clearBufferuiv(buffer, drawbuffer, value);
}
}
@@ -1802,43 +1571,13 @@ void GL_APIENTRY ClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat* v
Context *context = GetValidGlobalContext();
if (context)
{
- if (!ValidateClearBuffer(context))
+ if (!context->skipValidation() &&
+ !ValidateClearBufferfv(context, buffer, drawbuffer, value))
{
return;
}
- switch (buffer)
- {
- case GL_COLOR:
- if (drawbuffer < 0 || static_cast<GLuint>(drawbuffer) >= context->getCaps().maxDrawBuffers)
- {
- context->recordError(Error(GL_INVALID_VALUE));
- return;
- }
- break;
-
- case GL_DEPTH:
- if (drawbuffer != 0)
- {
- context->recordError(Error(GL_INVALID_VALUE));
- return;
- }
- break;
-
- default:
- context->recordError(Error(GL_INVALID_ENUM));
- return;
- }
-
- Framebuffer *framebufferObject = context->getState().getDrawFramebuffer();
- ASSERT(framebufferObject);
-
- Error error = framebufferObject->clearBufferfv(context->getState(), buffer, drawbuffer, value);
- if (error.isError())
- {
- context->recordError(error);
- return;
- }
+ context->clearBufferfv(buffer, drawbuffer, value);
}
}
@@ -1850,35 +1589,13 @@ void GL_APIENTRY ClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, G
Context *context = GetValidGlobalContext();
if (context)
{
- if (!ValidateClearBuffer(context))
+ if (!context->skipValidation() &&
+ !ValidateClearBufferfi(context, buffer, drawbuffer, depth, stencil))
{
return;
}
- switch (buffer)
- {
- case GL_DEPTH_STENCIL:
- if (drawbuffer != 0)
- {
- context->recordError(Error(GL_INVALID_VALUE));
- return;
- }
- break;
-
- default:
- context->recordError(Error(GL_INVALID_ENUM));
- return;
- }
-
- Framebuffer *framebufferObject = context->getState().getDrawFramebuffer();
- ASSERT(framebufferObject);
-
- Error error = framebufferObject->clearBufferfi(context->getState(), buffer, drawbuffer, depth, stencil);
- if (error.isError())
- {
- context->recordError(error);
- return;
- }
+ context->clearBufferfi(buffer, drawbuffer, depth, stencil);
}
}
@@ -1996,20 +1713,11 @@ void GL_APIENTRY GetUniformIndices(GLuint program, GLsizei uniformCount, const G
return;
}
- Program *programObject = context->getProgram(program);
+ Program *programObject = GetValidProgram(context, program);
if (!programObject)
{
- if (context->getShader(program))
- {
- context->recordError(Error(GL_INVALID_OPERATION));
- return;
- }
- else
- {
- context->recordError(Error(GL_INVALID_VALUE));
- return;
- }
+ return;
}
if (!programObject->isLinked())
@@ -2049,20 +1757,11 @@ void GL_APIENTRY GetActiveUniformsiv(GLuint program, GLsizei uniformCount, const
return;
}
- Program *programObject = context->getProgram(program);
+ Program *programObject = GetValidProgram(context, program);
if (!programObject)
{
- if (context->getShader(program))
- {
- context->recordError(Error(GL_INVALID_OPERATION));
- return;
- }
- else
- {
- context->recordError(Error(GL_INVALID_VALUE));
- return;
- }
+ return;
}
switch (pname)
@@ -2120,20 +1819,10 @@ GLuint GL_APIENTRY GetUniformBlockIndex(GLuint program, const GLchar* uniformBlo
return GL_INVALID_INDEX;
}
- Program *programObject = context->getProgram(program);
-
+ Program *programObject = GetValidProgram(context, program);
if (!programObject)
{
- if (context->getShader(program))
- {
- context->recordError(Error(GL_INVALID_OPERATION));
- return GL_INVALID_INDEX;
- }
- else
- {
- context->recordError(Error(GL_INVALID_VALUE));
- return GL_INVALID_INDEX;
- }
+ return GL_INVALID_INDEX;
}
return programObject->getUniformBlockIndex(uniformBlockName);
@@ -2155,20 +1844,11 @@ void GL_APIENTRY GetActiveUniformBlockiv(GLuint program, GLuint uniformBlockInde
context->recordError(Error(GL_INVALID_OPERATION));
return;
}
- Program *programObject = context->getProgram(program);
+ Program *programObject = GetValidProgram(context, program);
if (!programObject)
{
- if (context->getShader(program))
- {
- context->recordError(Error(GL_INVALID_OPERATION));
- return;
- }
- else
- {
- context->recordError(Error(GL_INVALID_VALUE));
- return;
- }
+ return;
}
if (uniformBlockIndex >= programObject->getActiveUniformBlockCount())
@@ -2213,20 +1893,11 @@ void GL_APIENTRY GetActiveUniformBlockName(GLuint program, GLuint uniformBlockIn
return;
}
- Program *programObject = context->getProgram(program);
+ Program *programObject = GetValidProgram(context, program);
if (!programObject)
{
- if (context->getShader(program))
- {
- context->recordError(Error(GL_INVALID_OPERATION));
- return;
- }
- else
- {
- context->recordError(Error(GL_INVALID_VALUE));
- return;
- }
+ return;
}
if (uniformBlockIndex >= programObject->getActiveUniformBlockCount())
@@ -2259,20 +1930,11 @@ void GL_APIENTRY UniformBlockBinding(GLuint program, GLuint uniformBlockIndex, G
return;
}
- Program *programObject = context->getProgram(program);
+ Program *programObject = GetValidProgram(context, program);
if (!programObject)
{
- if (context->getShader(program))
- {
- context->recordError(Error(GL_INVALID_OPERATION));
- return;
- }
- else
- {
- context->recordError(Error(GL_INVALID_VALUE));
- return;
- }
+ return;
}
// if never linked, there won't be any uniform blocks
@@ -2305,7 +1967,7 @@ void GL_APIENTRY DrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GL
return;
}
- Error error = context->drawArrays(mode, first, count, instanceCount);
+ Error error = context->drawArraysInstanced(mode, first, count, instanceCount);
if (error.isError())
{
context->recordError(error);
@@ -2328,13 +1990,14 @@ void GL_APIENTRY DrawElementsInstanced(GLenum mode, GLsizei count, GLenum type,
return;
}
- rx::RangeUI indexRange;
+ IndexRange indexRange;
if (!ValidateDrawElementsInstanced(context, mode, count, type, indices, instanceCount, &indexRange))
{
return;
}
- Error error = context->drawElements(mode, count, type, indices, instanceCount, indexRange);
+ Error error =
+ context->drawElementsInstanced(mode, count, type, indices, instanceCount, indexRange);
if (error.isError())
{
context->recordError(error);
@@ -2371,7 +2034,7 @@ GLsync GL_APIENTRY FenceSync_(GLenum condition, GLbitfield flags)
GLsync fenceSync = context->createFenceSync();
FenceSync *fenceSyncObject = context->getFenceSync(fenceSync);
- Error error = fenceSyncObject->set(condition);
+ Error error = fenceSyncObject->set(condition, flags);
if (error.isError())
{
context->deleteFenceSync(fenceSync);
@@ -2575,7 +2238,7 @@ void GL_APIENTRY GetSynciv(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei*
{
case GL_OBJECT_TYPE: values[0] = static_cast<GLint>(GL_SYNC_FENCE); break;
case GL_SYNC_CONDITION: values[0] = static_cast<GLint>(fenceSync->getCondition()); break;
- case GL_SYNC_FLAGS: values[0] = 0; break;
+ case GL_SYNC_FLAGS: values[0] = static_cast<GLint>(fenceSync->getFlags()); break;
case GL_SYNC_STATUS:
{
@@ -3005,16 +2668,18 @@ void GL_APIENTRY BindTransformFeedback(GLenum target, GLuint id)
{
// Cannot bind a transform feedback object if the current one is started and not paused (3.0.2 pg 85 section 2.14.1)
TransformFeedback *curTransformFeedback = context->getState().getCurrentTransformFeedback();
- if (curTransformFeedback && curTransformFeedback->isStarted() && !curTransformFeedback->isPaused())
+ if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused())
{
context->recordError(Error(GL_INVALID_OPERATION));
return;
}
// Cannot bind a transform feedback object that does not exist (3.0.2 pg 85 section 2.14.1)
- if (context->getTransformFeedback(id) == NULL)
+ if (!context->isTransformFeedbackGenerated(id))
{
- context->recordError(Error(GL_INVALID_OPERATION));
+ context->recordError(
+ Error(GL_INVALID_OPERATION,
+ "Cannot bind a transform feedback object that does not exist."));
return;
}
@@ -3082,7 +2747,15 @@ GLboolean GL_APIENTRY IsTransformFeedback(GLuint id)
return GL_FALSE;
}
- return ((context->getTransformFeedback(id) != NULL) ? GL_TRUE : GL_FALSE);
+ if (id == 0)
+ {
+ // The 3.0.4 spec [section 6.1.11] states that if ID is zero, IsTransformFeedback
+ // returns FALSE
+ return GL_FALSE;
+ }
+
+ const TransformFeedback *transformFeedback = context->getTransformFeedback(id);
+ return ((transformFeedback != nullptr) ? GL_TRUE : GL_FALSE);
}
return GL_FALSE;
@@ -3104,8 +2777,8 @@ void GL_APIENTRY PauseTransformFeedback(void)
TransformFeedback *transformFeedback = context->getState().getCurrentTransformFeedback();
ASSERT(transformFeedback != NULL);
- // Current transform feedback must be started and not paused in order to pause (3.0.2 pg 86)
- if (!transformFeedback->isStarted() || transformFeedback->isPaused())
+ // Current transform feedback must be active and not paused in order to pause (3.0.2 pg 86)
+ if (!transformFeedback->isActive() || transformFeedback->isPaused())
{
context->recordError(Error(GL_INVALID_OPERATION));
return;
@@ -3131,8 +2804,8 @@ void GL_APIENTRY ResumeTransformFeedback(void)
TransformFeedback *transformFeedback = context->getState().getCurrentTransformFeedback();
ASSERT(transformFeedback != NULL);
- // Current transform feedback must be started and paused in order to resume (3.0.2 pg 86)
- if (!transformFeedback->isStarted() || !transformFeedback->isPaused())
+ // Current transform feedback must be active and paused in order to resume (3.0.2 pg 86)
+ if (!transformFeedback->isActive() || !transformFeedback->isPaused())
{
context->recordError(Error(GL_INVALID_OPERATION));
return;
@@ -3150,14 +2823,20 @@ void GL_APIENTRY GetProgramBinary(GLuint program, GLsizei bufSize, GLsizei* leng
Context *context = GetValidGlobalContext();
if (context)
{
- if (context->getClientVersion() < 3)
+ if (!ValidateGetProgramBinary(context, program, bufSize, length, binaryFormat, binary))
{
- context->recordError(Error(GL_INVALID_OPERATION));
return;
}
- // TODO: Pipe through to the OES extension for now, needs proper validation
- return GetProgramBinaryOES(program, bufSize, length, binaryFormat, binary);
+ Program *programObject = context->getProgram(program);
+ ASSERT(programObject != nullptr);
+
+ Error error = programObject->saveBinary(binaryFormat, binary, bufSize, length);
+ if (error.isError())
+ {
+ context->recordError(error);
+ return;
+ }
}
}
@@ -3169,14 +2848,20 @@ void GL_APIENTRY ProgramBinary(GLuint program, GLenum binaryFormat, const GLvoid
Context *context = GetValidGlobalContext();
if (context)
{
- if (context->getClientVersion() < 3)
+ if (!ValidateProgramBinary(context, program, binaryFormat, binary, length))
{
- context->recordError(Error(GL_INVALID_OPERATION));
return;
}
- // TODO: Pipe through to the OES extension for now, needs proper validation
- return ProgramBinaryOES(program, binaryFormat, binary, length);
+ Program *programObject = context->getProgram(program);
+ ASSERT(programObject != nullptr);
+
+ Error error = programObject->loadBinary(binaryFormat, binary, length);
+ if (error.isError())
+ {
+ context->recordError(error);
+ return;
+ }
}
}
@@ -3188,14 +2873,23 @@ void GL_APIENTRY ProgramParameteri(GLuint program, GLenum pname, GLint value)
Context *context = GetValidGlobalContext();
if (context)
{
- if (context->getClientVersion() < 3)
+ if (!ValidateProgramParameter(context, program, pname, value))
{
- context->recordError(Error(GL_INVALID_OPERATION));
return;
}
- // glProgramParameteri
- UNIMPLEMENTED();
+ gl::Program *programObject = context->getProgram(program);
+ ASSERT(programObject != nullptr);
+
+ switch (pname)
+ {
+ case GL_PROGRAM_BINARY_RETRIEVABLE_HINT:
+ programObject->setBinaryRetrievableHint(value != GL_FALSE);
+ break;
+
+ default:
+ UNREACHABLE();
+ }
}
}
@@ -3207,29 +2901,13 @@ void GL_APIENTRY InvalidateFramebuffer(GLenum target, GLsizei numAttachments, co
Context *context = GetValidGlobalContext();
if (context)
{
- if (context->getClientVersion() < 3)
- {
- context->recordError(Error(GL_INVALID_OPERATION));
- return;
- }
-
- if (!ValidateInvalidateFramebufferParameters(context, target, numAttachments, attachments))
+ if (!context->skipValidation() &&
+ !ValidateInvalidateFramebuffer(context, target, numAttachments, attachments))
{
return;
}
- Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
- ASSERT(framebuffer);
-
- if (framebuffer->checkStatus(context->getData()) == GL_FRAMEBUFFER_COMPLETE)
- {
- Error error = framebuffer->invalidate(numAttachments, attachments);
- if (error.isError())
- {
- context->recordError(error);
- return;
- }
- }
+ context->invalidateFramebuffer(target, numAttachments, attachments);
}
}
@@ -3242,30 +2920,13 @@ void GL_APIENTRY InvalidateSubFramebuffer(GLenum target, GLsizei numAttachments,
Context *context = GetValidGlobalContext();
if (context)
{
- if (context->getClientVersion() < 3)
+ if (!context->skipValidation() &&
+ !ValidateInvalidateFramebuffer(context, target, numAttachments, attachments))
{
- context->recordError(Error(GL_INVALID_OPERATION));
return;
}
- if (!ValidateInvalidateFramebufferParameters(context, target, numAttachments, attachments))
- {
- return;
- }
-
- Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
- ASSERT(framebuffer);
-
- if (framebuffer->checkStatus(context->getData()) == GL_FRAMEBUFFER_COMPLETE)
- {
- Rectangle area(x, y, width, height);
- Error error = framebuffer->invalidateSub(numAttachments, attachments, area);
- if (error.isError())
- {
- context->recordError(error);
- return;
- }
- }
+ context->invalidateSubFramebuffer(target, numAttachments, attachments, x, y, width, height);
}
}
@@ -3283,7 +2944,8 @@ void GL_APIENTRY TexStorage2D(GLenum target, GLsizei levels, GLenum internalform
return;
}
- if (!ValidateES3TexStorageParameters(context, target, levels, internalformat, width, height, 1))
+ if (!ValidateES3TexStorage2DParameters(context, target, levels, internalformat, width,
+ height, 1))
{
return;
}
@@ -3314,7 +2976,8 @@ void GL_APIENTRY TexStorage3D(GLenum target, GLsizei levels, GLenum internalform
return;
}
- if (!ValidateES3TexStorageParameters(context, target, levels, internalformat, width, height, depth))
+ if (!ValidateES3TexStorage3DParameters(context, target, levels, internalformat, width,
+ height, depth))
{
return;
}
@@ -3369,7 +3032,7 @@ void GL_APIENTRY GetInternalformativ(GLenum target, GLenum internalformat, GLenu
case GL_NUM_SAMPLE_COUNTS:
if (bufSize != 0)
{
- *params = formatCaps.sampleCounts.size();
+ *params = static_cast<GLint>(formatCaps.sampleCounts.size());
}
break;
diff --git a/src/3rdparty/angle/src/libGLESv2/global_state.cpp b/src/3rdparty/angle/src/libGLESv2/global_state.cpp
index 686f0bf49b..b99c3e1ca9 100644
--- a/src/3rdparty/angle/src/libGLESv2/global_state.cpp
+++ b/src/3rdparty/angle/src/libGLESv2/global_state.cpp
@@ -55,13 +55,6 @@ Current *AllocateCurrent()
return current;
}
-void DeallocateCurrent()
-{
- Current *current = reinterpret_cast<Current*>(GetTLSValue(currentTLS));
- SafeDelete(current);
- SetTLSValue(currentTLS, NULL);
-}
-
Current *GetCurrentData()
{
// Create a TLS index if one has not been created for this DLL
@@ -78,6 +71,14 @@ Current *GetCurrentData()
}
#ifdef ANGLE_PLATFORM_WINDOWS
+
+void DeallocateCurrent()
+{
+ Current *current = reinterpret_cast<Current*>(GetTLSValue(currentTLS));
+ SafeDelete(current);
+ SetTLSValue(currentTLS, NULL);
+}
+
extern "C" BOOL WINAPI DllMain(HINSTANCE, DWORD reason, LPVOID)
{
switch (reason)
diff --git a/src/3rdparty/angle/src/libGLESv2/libGLESv2.cpp b/src/3rdparty/angle/src/libGLESv2/libGLESv2.cpp
index e69e04aa60..42b749f373 100644
--- a/src/3rdparty/angle/src/libGLESv2/libGLESv2.cpp
+++ b/src/3rdparty/angle/src/libGLESv2/libGLESv2.cpp
@@ -9,7 +9,6 @@
#include "libGLESv2/entry_points_gles_2_0.h"
#include "libGLESv2/entry_points_gles_2_0_ext.h"
#include "libGLESv2/entry_points_gles_3_0.h"
-#include "libGLESv2/entry_points_gles_3_0_ext.h"
#include "common/event_tracer.h"
@@ -1256,6 +1255,11 @@ void GL_APIENTRY glRenderbufferStorageMultisampleANGLE(GLenum target, GLsizei sa
return gl::RenderbufferStorageMultisampleANGLE(target, samples, internalformat, width, height);
}
+void GL_APIENTRY glDiscardFramebufferEXT(GLenum target, GLsizei numAttachments, const GLenum *attachments)
+{
+ return gl::DiscardFramebufferEXT(target, numAttachments, attachments);
+}
+
void GL_APIENTRY glDeleteFencesNV(GLsizei n, const GLuint* fences)
{
return gl::DeleteFencesNV(n, fences);
@@ -1346,16 +1350,36 @@ void GL_APIENTRY glEndQueryEXT(GLenum target)
return gl::EndQueryEXT(target);
}
+void GL_APIENTRY glQueryCounterEXT(GLuint id, GLenum target)
+{
+ return gl::QueryCounterEXT(id, target);
+}
+
void GL_APIENTRY glGetQueryivEXT(GLenum target, GLenum pname, GLint *params)
{
return gl::GetQueryivEXT(target, pname, params);
}
+void GL_APIENTRY glGetQueryObjectivEXT(GLuint id, GLenum pname, GLint *params)
+{
+ return gl::GetQueryObjectivEXT(id, pname, params);
+}
+
void GL_APIENTRY glGetQueryObjectuivEXT(GLuint id, GLenum pname, GLuint *params)
{
return gl::GetQueryObjectuivEXT(id, pname, params);
}
+void GL_APIENTRY glGetQueryObjecti64vEXT(GLuint id, GLenum pname, GLint64 *params)
+{
+ return gl::GetQueryObjecti64vEXT(id, pname, params);
+}
+
+void GL_APIENTRY glGetQueryObjectui64vEXT(GLuint id, GLenum pname, GLuint64 *params)
+{
+ return gl::GetQueryObjectui64vEXT(id, pname, params);
+}
+
void GL_APIENTRY glDrawBuffersEXT(GLsizei n, const GLenum *bufs)
{
return gl::DrawBuffersEXT(n, bufs);
@@ -1411,11 +1435,131 @@ void GL_APIENTRY glFlushMappedBufferRangeEXT(GLenum target, GLintptr offset, GLs
return gl::FlushMappedBufferRangeEXT(target, offset, length);
}
-void GL_APIENTRY SetTraceFunctionPointers(GetCategoryEnabledFlagFunc getCategoryEnabledFlag,
- AddTraceEventFunc addTraceEvent)
+void GL_APIENTRY glInsertEventMarkerEXT(GLsizei length, const char *marker)
+{
+ return gl::InsertEventMarkerEXT(length, marker);
+}
+
+void GL_APIENTRY glPushGroupMarkerEXT(GLsizei length, const char *marker)
+{
+ return gl::PushGroupMarkerEXT(length, marker);
+}
+
+void GL_APIENTRY glPopGroupMarkerEXT()
+{
+ return gl::PopGroupMarkerEXT();
+}
+
+void GL_APIENTRY glEGLImageTargetTexture2DOES(GLenum target, GLeglImageOES image)
+{
+ return gl::EGLImageTargetTexture2DOES(target, image);
+}
+
+void GL_APIENTRY glEGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image)
+{
+ return gl::EGLImageTargetRenderbufferStorageOES(target, image);
+}
+
+void GL_APIENTRY glBindVertexArrayOES(GLuint array)
+{
+ return gl::BindVertexArrayOES(array);
+}
+
+void GL_APIENTRY glDeleteVertexArraysOES(GLsizei n, const GLuint *arrays)
+{
+ return gl::DeleteVertexArraysOES(n, arrays);
+}
+
+void GL_APIENTRY glGenVertexArraysOES(GLsizei n, GLuint *arrays)
{
- gl::g_getCategoryEnabledFlag = getCategoryEnabledFlag;
- gl::g_addTraceEvent = addTraceEvent;
+ return gl::GenVertexArraysOES(n, arrays);
}
+GLboolean GL_APIENTRY glIsVertexArrayOES(GLuint array)
+{
+ return gl::IsVertexArrayOES(array);
+}
+
+void GL_APIENTRY glDebugMessageControlKHR(GLenum source,
+ GLenum type,
+ GLenum severity,
+ GLsizei count,
+ const GLuint *ids,
+ GLboolean enabled)
+{
+ return gl::DebugMessageControlKHR(source, type, severity, count, ids, enabled);
+}
+
+void GL_APIENTRY glDebugMessageInsertKHR(GLenum source,
+ GLenum type,
+ GLuint id,
+ GLenum severity,
+ GLsizei length,
+ const GLchar *buf)
+{
+ return gl::DebugMessageInsertKHR(source, type, id, severity, length, buf);
+}
+
+void GL_APIENTRY glDebugMessageCallbackKHR(GLDEBUGPROCKHR callback, const void *userParam)
+{
+ return gl::DebugMessageCallbackKHR(callback, userParam);
+}
+
+GLuint GL_APIENTRY glGetDebugMessageLogKHR(GLuint count,
+ GLsizei bufSize,
+ GLenum *sources,
+ GLenum *types,
+ GLuint *ids,
+ GLenum *severities,
+ GLsizei *lengths,
+ GLchar *messageLog)
+{
+ return gl::GetDebugMessageLogKHR(count, bufSize, sources, types, ids, severities, lengths,
+ messageLog);
+}
+
+void GL_APIENTRY glPushDebugGroupKHR(GLenum source,
+ GLuint id,
+ GLsizei length,
+ const GLchar *message)
+{
+ return gl::PushDebugGroupKHR(source, id, length, message);
+}
+
+void GL_APIENTRY glPopDebugGroupKHR(void)
+{
+ return gl::PopDebugGroupKHR();
+}
+
+void GL_APIENTRY glObjectLabelKHR(GLenum identifier,
+ GLuint name,
+ GLsizei length,
+ const GLchar *label)
+{
+ return gl::ObjectLabelKHR(identifier, name, length, label);
+}
+
+void GL_APIENTRY
+glGetObjectLabelKHR(GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label)
+{
+ return gl::GetObjectLabelKHR(identifier, name, bufSize, length, label);
+}
+
+void GL_APIENTRY glObjectPtrLabelKHR(const void *ptr, GLsizei length, const GLchar *label)
+{
+ return gl::ObjectPtrLabelKHR(ptr, length, label);
+}
+
+void GL_APIENTRY glGetObjectPtrLabelKHR(const void *ptr,
+ GLsizei bufSize,
+ GLsizei *length,
+ GLchar *label)
+{
+ return gl::GetObjectPtrLabelKHR(ptr, bufSize, length, label);
+}
+
+void GL_APIENTRY glGetPointervKHR(GLenum pname, void **params)
+{
+ return gl::GetPointervKHR(pname, params);
+}
}
diff --git a/src/3rdparty/angle/src/libGLESv2/libGLESv2.def b/src/3rdparty/angle/src/libGLESv2/libGLESv2.def
index 9c6dc497d0..0aebb6c864 100644
--- a/src/3rdparty/angle/src/libGLESv2/libGLESv2.def
+++ b/src/3rdparty/angle/src/libGLESv2/libGLESv2.def
@@ -177,6 +177,31 @@ EXPORTS
glGetBufferPointervOES @287
glMapBufferRangeEXT @288
glFlushMappedBufferRangeEXT @289
+ glDiscardFramebufferEXT @293
+ glInsertEventMarkerEXT @294
+ glPushGroupMarkerEXT @295
+ glPopGroupMarkerEXT @296
+ glEGLImageTargetTexture2DOES @297
+ glEGLImageTargetRenderbufferStorageOES @298
+ glBindVertexArrayOES @299
+ glDeleteVertexArraysOES @300
+ glGenVertexArraysOES @301
+ glIsVertexArrayOES @302
+ glDebugMessageControlKHR @303
+ glDebugMessageInsertKHR @304
+ glDebugMessageCallbackKHR @305
+ glGetDebugMessageLogKHR @306
+ glPushDebugGroupKHR @307
+ glPopDebugGroupKHR @308
+ glObjectLabelKHR @309
+ glGetObjectLabelKHR @310
+ glObjectPtrLabelKHR @311
+ glGetObjectPtrLabelKHR @312
+ glGetPointervKHR @313
+ glQueryCounterEXT @314
+ glGetQueryObjectivEXT @315
+ glGetQueryObjecti64vEXT @316
+ glGetQueryObjectui64vEXT @317
; GLES 3.0 Functions
glReadBuffer @180
@@ -284,5 +309,7 @@ EXPORTS
glTexStorage3D @282
glGetInternalformativ @283
- ; Setting up TRACE macro callbacks
- SetTraceFunctionPointers @284
+ ; ANGLE Platform Implementation
+ ANGLEPlatformCurrent @290
+ ANGLEPlatformInitialize @291
+ ANGLEPlatformShutdown @292
diff --git a/src/3rdparty/angle/src/libGLESv2/libGLESv2_mingw32.def b/src/3rdparty/angle/src/libGLESv2/libGLESv2_mingw32.def
index e02b85bcf2..db17bb487b 100644
--- a/src/3rdparty/angle/src/libGLESv2/libGLESv2_mingw32.def
+++ b/src/3rdparty/angle/src/libGLESv2/libGLESv2_mingw32.def
@@ -177,6 +177,31 @@ EXPORTS
glGetBufferPointervOES@12 @287
glMapBufferRangeEXT@16 @288
glFlushMappedBufferRangeEXT@12 @289
+ glDiscardFramebufferEXT@12 @293
+ glInsertEventMarkerEXT@8 @294
+ glPushGroupMarkerEXT@8 @295
+ glPopGroupMarkerEXT@0 @296
+ glEGLImageTargetTexture2DOES@8 @297
+ glEGLImageTargetRenderbufferStorageOES@8 @298
+ glBindVertexArrayOES@4 @299
+ glDeleteVertexArraysOES@8 @300
+ glGenVertexArraysOES@8 @301
+ glIsVertexArrayOES@4 @302
+ glDebugMessageControlKHR@24 @303
+ glDebugMessageInsertKHR@24 @304
+ glDebugMessageCallbackKHR@8 @305
+ glGetDebugMessageLogKHR@32 @306
+ glPushDebugGroupKHR@16 @307
+ glPopDebugGroupKHR@0 @308
+ glObjectLabelKHR@16 @309
+ glGetObjectLabelKHR@20 @310
+ glObjectPtrLabelKHR@12 @311
+ glGetObjectPtrLabelKHR@16 @312
+ glGetPointervKHR@8 @313
+ glQueryCounterEXT@8 @314
+ glGetQueryObjectivEXT@12 @315
+ glGetQueryObjecti64vEXT@12 @316
+ glGetQueryObjectui64vEXT@12 @317
; GLES 3.0 Functions
glReadBuffer@4 @180
@@ -284,5 +309,8 @@ EXPORTS
glTexStorage3D@24 @282
glGetInternalformativ@20 @283
- ; Setting up TRACE macro callbacks
- SetTraceFunctionPointers@8 @284
+ ; ANGLE Platform Implementation
+ ANGLEPlatformCurrent@0 @290
+ ANGLEPlatformInitialize@4 @291
+ ANGLEPlatformShutdown@0 @292
+ \ No newline at end of file
diff --git a/src/3rdparty/angle/src/libGLESv2/libGLESv2d.def b/src/3rdparty/angle/src/libGLESv2/libGLESv2d.def
index d35309c6ce..e0c3823abf 100644
--- a/src/3rdparty/angle/src/libGLESv2/libGLESv2d.def
+++ b/src/3rdparty/angle/src/libGLESv2/libGLESv2d.def
@@ -177,6 +177,31 @@ EXPORTS
glGetBufferPointervOES @287
glMapBufferRangeEXT @288
glFlushMappedBufferRangeEXT @289
+ glDiscardFramebufferEXT @293
+ glInsertEventMarkerEXT @294
+ glPushGroupMarkerEXT @295
+ glPopGroupMarkerEXT @296
+ glEGLImageTargetTexture2DOES @297
+ glEGLImageTargetRenderbufferStorageOES @298
+ glBindVertexArrayOES @299
+ glDeleteVertexArraysOES @300
+ glGenVertexArraysOES @301
+ glIsVertexArrayOES @302
+ glDebugMessageControlKHR @303
+ glDebugMessageInsertKHR @304
+ glDebugMessageCallbackKHR @305
+ glGetDebugMessageLogKHR @306
+ glPushDebugGroupKHR @307
+ glPopDebugGroupKHR @308
+ glObjectLabelKHR @309
+ glGetObjectLabelKHR @310
+ glObjectPtrLabelKHR @311
+ glGetObjectPtrLabelKHR @312
+ glGetPointervKHR @313
+ glQueryCounterEXT @314
+ glGetQueryObjectivEXT @315
+ glGetQueryObjecti64vEXT @316
+ glGetQueryObjectui64vEXT @317
; GLES 3.0 Functions
glReadBuffer @180
@@ -284,5 +309,7 @@ EXPORTS
glTexStorage3D @282
glGetInternalformativ @283
- ; Setting up TRACE macro callbacks
- SetTraceFunctionPointers @284
+ ; ANGLE Platform Implementation
+ ANGLEPlatformCurrent @290
+ ANGLEPlatformInitialize @291
+ ANGLEPlatformShutdown @292
diff --git a/src/3rdparty/angle/src/libGLESv2/libGLESv2d_mingw32.def b/src/3rdparty/angle/src/libGLESv2/libGLESv2d_mingw32.def
index e2b2c333a1..5a4966f66d 100644
--- a/src/3rdparty/angle/src/libGLESv2/libGLESv2d_mingw32.def
+++ b/src/3rdparty/angle/src/libGLESv2/libGLESv2d_mingw32.def
@@ -177,6 +177,31 @@ EXPORTS
glGetBufferPointervOES@12 @287
glMapBufferRangeEXT@16 @288
glFlushMappedBufferRangeEXT@12 @289
+ glDiscardFramebufferEXT@12 @293
+ glInsertEventMarkerEXT@8 @294
+ glPushGroupMarkerEXT@8 @295
+ glPopGroupMarkerEXT@0 @296
+ glEGLImageTargetTexture2DOES@8 @297
+ glEGLImageTargetRenderbufferStorageOES@8 @298
+ glBindVertexArrayOES@4 @299
+ glDeleteVertexArraysOES@8 @300
+ glGenVertexArraysOES@8 @301
+ glIsVertexArrayOES@4 @302
+ glDebugMessageControlKHR@24 @303
+ glDebugMessageInsertKHR@24 @304
+ glDebugMessageCallbackKHR@8 @305
+ glGetDebugMessageLogKHR@32 @306
+ glPushDebugGroupKHR@16 @307
+ glPopDebugGroupKHR@0 @308
+ glObjectLabelKHR@16 @309
+ glGetObjectLabelKHR@20 @310
+ glObjectPtrLabelKHR@12 @311
+ glGetObjectPtrLabelKHR@16 @312
+ glGetPointervKHR@8 @313
+ glQueryCounterEXT@8 @314
+ glGetQueryObjectivEXT@12 @315
+ glGetQueryObjecti64vEXT@12 @316
+ glGetQueryObjectui64vEXT@12 @317
; GLES 3.0 Functions
glReadBuffer@4 @180
@@ -284,5 +309,8 @@ EXPORTS
glTexStorage3D@24 @282
glGetInternalformativ@20 @283
- ; Setting up TRACE macro callbacks
- SetTraceFunctionPointers@8 @284
+ ; ANGLE Platform Implementation
+ ANGLEPlatformCurrent@0 @290
+ ANGLEPlatformInitialize@4 @291
+ ANGLEPlatformShutdown@0 @292
+ \ No newline at end of file
diff --git a/src/3rdparty/angle/src/third_party/compiler/ArrayBoundsClamper.cpp b/src/3rdparty/angle/src/third_party/compiler/ArrayBoundsClamper.cpp
index 288f5529ad..fa6c8b8d79 100644
--- a/src/3rdparty/angle/src/third_party/compiler/ArrayBoundsClamper.cpp
+++ b/src/3rdparty/angle/src/third_party/compiler/ArrayBoundsClamper.cpp
@@ -43,11 +43,12 @@ namespace {
class ArrayBoundsClamperMarker : public TIntermTraverser {
public:
ArrayBoundsClamperMarker()
- : mNeedsClamp(false)
+ : TIntermTraverser(true, false, false),
+ mNeedsClamp(false)
{
}
- virtual bool visitBinary(Visit visit, TIntermBinary* node)
+ bool visitBinary(Visit visit, TIntermBinary *node) override
{
if (node->getOp() == EOpIndexIndirect)
{
diff --git a/src/3rdparty/angle/src/third_party/murmurhash/MurmurHash3.cpp b/src/3rdparty/angle/src/third_party/murmurhash/MurmurHash3.cpp
index a599c26502..aa7982d3ee 100644
--- a/src/3rdparty/angle/src/third_party/murmurhash/MurmurHash3.cpp
+++ b/src/3rdparty/angle/src/third_party/murmurhash/MurmurHash3.cpp
@@ -29,9 +29,7 @@
#else // defined(_MSC_VER)
-// Ignore GCC force inline warnings
-#pragma GCC diagnostic ignored "-Wattributes"
-#define FORCE_INLINE __attribute__((always_inline))
+#define FORCE_INLINE inline __attribute__((always_inline))
inline uint32_t rotl32 ( uint32_t x, int8_t r )
{
@@ -54,12 +52,12 @@ inline uint64_t rotl64 ( uint64_t x, int8_t r )
// Block read - if your platform needs to do endian-swapping or can only
// handle aligned reads, do the conversion here
-FORCE_INLINE uint32_t getblock ( const uint32_t * p, int i )
+FORCE_INLINE uint32_t getblock32 ( const uint32_t * p, int i )
{
return p[i];
}
-FORCE_INLINE uint64_t getblock ( const uint64_t * p, int i )
+FORCE_INLINE uint64_t getblock64 ( const uint64_t * p, int i )
{
return p[i];
}
@@ -67,7 +65,7 @@ FORCE_INLINE uint64_t getblock ( const uint64_t * p, int i )
//-----------------------------------------------------------------------------
// Finalization mix - force all bits of a hash block to avalanche
-FORCE_INLINE uint32_t fmix ( uint32_t h )
+FORCE_INLINE uint32_t fmix32 ( uint32_t h )
{
h ^= h >> 16;
h *= 0x85ebca6b;
@@ -80,7 +78,7 @@ FORCE_INLINE uint32_t fmix ( uint32_t h )
//----------
-FORCE_INLINE uint64_t fmix ( uint64_t k )
+FORCE_INLINE uint64_t fmix64 ( uint64_t k )
{
k ^= k >> 33;
k *= BIG_CONSTANT(0xff51afd7ed558ccd);
@@ -111,7 +109,7 @@ void MurmurHash3_x86_32 ( const void * key, int len,
for(int i = -nblocks; i; i++)
{
- uint32_t k1 = getblock(blocks,i);
+ uint32_t k1 = getblock32(blocks,i);
k1 *= c1;
k1 = ROTL32(k1,15);
@@ -142,7 +140,7 @@ void MurmurHash3_x86_32 ( const void * key, int len,
h1 ^= len;
- h1 = fmix(h1);
+ h1 = fmix32(h1);
*(uint32_t*)out = h1;
}
@@ -172,10 +170,10 @@ void MurmurHash3_x86_128 ( const void * key, const int len,
for(int i = -nblocks; i; i++)
{
- uint32_t k1 = getblock(blocks,i*4+0);
- uint32_t k2 = getblock(blocks,i*4+1);
- uint32_t k3 = getblock(blocks,i*4+2);
- uint32_t k4 = getblock(blocks,i*4+3);
+ uint32_t k1 = getblock32(blocks,i*4+0);
+ uint32_t k2 = getblock32(blocks,i*4+1);
+ uint32_t k3 = getblock32(blocks,i*4+2);
+ uint32_t k4 = getblock32(blocks,i*4+3);
k1 *= c1; k1 = ROTL32(k1,15); k1 *= c2; h1 ^= k1;
@@ -238,10 +236,10 @@ void MurmurHash3_x86_128 ( const void * key, const int len,
h1 += h2; h1 += h3; h1 += h4;
h2 += h1; h3 += h1; h4 += h1;
- h1 = fmix(h1);
- h2 = fmix(h2);
- h3 = fmix(h3);
- h4 = fmix(h4);
+ h1 = fmix32(h1);
+ h2 = fmix32(h2);
+ h3 = fmix32(h3);
+ h4 = fmix32(h4);
h1 += h2; h1 += h3; h1 += h4;
h2 += h1; h3 += h1; h4 += h1;
@@ -273,8 +271,8 @@ void MurmurHash3_x64_128 ( const void * key, const int len,
for(int i = 0; i < nblocks; i++)
{
- uint64_t k1 = getblock(blocks,i*2+0);
- uint64_t k2 = getblock(blocks,i*2+1);
+ uint64_t k1 = getblock64(blocks,i*2+0);
+ uint64_t k2 = getblock64(blocks,i*2+1);
k1 *= c1; k1 = ROTL64(k1,31); k1 *= c2; h1 ^= k1;
@@ -295,23 +293,23 @@ void MurmurHash3_x64_128 ( const void * key, const int len,
switch(len & 15)
{
- case 15: k2 ^= uint64_t(tail[14]) << 48;
- case 14: k2 ^= uint64_t(tail[13]) << 40;
- case 13: k2 ^= uint64_t(tail[12]) << 32;
- case 12: k2 ^= uint64_t(tail[11]) << 24;
- case 11: k2 ^= uint64_t(tail[10]) << 16;
- case 10: k2 ^= uint64_t(tail[ 9]) << 8;
- case 9: k2 ^= uint64_t(tail[ 8]) << 0;
+ case 15: k2 ^= ((uint64_t)tail[14]) << 48;
+ case 14: k2 ^= ((uint64_t)tail[13]) << 40;
+ case 13: k2 ^= ((uint64_t)tail[12]) << 32;
+ case 12: k2 ^= ((uint64_t)tail[11]) << 24;
+ case 11: k2 ^= ((uint64_t)tail[10]) << 16;
+ case 10: k2 ^= ((uint64_t)tail[ 9]) << 8;
+ case 9: k2 ^= ((uint64_t)tail[ 8]) << 0;
k2 *= c2; k2 = ROTL64(k2,33); k2 *= c1; h2 ^= k2;
- case 8: k1 ^= uint64_t(tail[ 7]) << 56;
- case 7: k1 ^= uint64_t(tail[ 6]) << 48;
- case 6: k1 ^= uint64_t(tail[ 5]) << 40;
- case 5: k1 ^= uint64_t(tail[ 4]) << 32;
- case 4: k1 ^= uint64_t(tail[ 3]) << 24;
- case 3: k1 ^= uint64_t(tail[ 2]) << 16;
- case 2: k1 ^= uint64_t(tail[ 1]) << 8;
- case 1: k1 ^= uint64_t(tail[ 0]) << 0;
+ case 8: k1 ^= ((uint64_t)tail[ 7]) << 56;
+ case 7: k1 ^= ((uint64_t)tail[ 6]) << 48;
+ case 6: k1 ^= ((uint64_t)tail[ 5]) << 40;
+ case 5: k1 ^= ((uint64_t)tail[ 4]) << 32;
+ case 4: k1 ^= ((uint64_t)tail[ 3]) << 24;
+ case 3: k1 ^= ((uint64_t)tail[ 2]) << 16;
+ case 2: k1 ^= ((uint64_t)tail[ 1]) << 8;
+ case 1: k1 ^= ((uint64_t)tail[ 0]) << 0;
k1 *= c1; k1 = ROTL64(k1,31); k1 *= c2; h1 ^= k1;
};
@@ -323,8 +321,8 @@ void MurmurHash3_x64_128 ( const void * key, const int len,
h1 += h2;
h2 += h1;
- h1 = fmix(h1);
- h2 = fmix(h2);
+ h1 = fmix64(h1);
+ h2 = fmix64(h2);
h1 += h2;
h2 += h1;
@@ -334,3 +332,4 @@ void MurmurHash3_x64_128 ( const void * key, const int len,
}
//-----------------------------------------------------------------------------
+
diff --git a/src/3rdparty/angle/src/third_party/murmurhash/MurmurHash3.h b/src/3rdparty/angle/src/third_party/murmurhash/MurmurHash3.h
index bb02cd508f..e1c6d34976 100644
--- a/src/3rdparty/angle/src/third_party/murmurhash/MurmurHash3.h
+++ b/src/3rdparty/angle/src/third_party/murmurhash/MurmurHash3.h
@@ -8,8 +8,22 @@
//-----------------------------------------------------------------------------
// Platform-specific functions and macros
+// Microsoft Visual Studio
+
+#if defined(_MSC_VER) && (_MSC_VER < 1600)
+
+typedef unsigned char uint8_t;
+typedef unsigned int uint32_t;
+typedef unsigned __int64 uint64_t;
+
+// Other compilers
+
+#else // defined(_MSC_VER)
+
#include <stdint.h>
+#endif // !defined(_MSC_VER)
+
//-----------------------------------------------------------------------------
void MurmurHash3_x86_32 ( const void * key, int len, uint32_t seed, void * out );
diff --git a/src/3rdparty/angle/src/third_party/systeminfo/SystemInfo.cpp b/src/3rdparty/angle/src/third_party/systeminfo/SystemInfo.cpp
index 97dfcaac51..fc05526681 100644
--- a/src/3rdparty/angle/src/third_party/systeminfo/SystemInfo.cpp
+++ b/src/3rdparty/angle/src/third_party/systeminfo/SystemInfo.cpp
@@ -26,7 +26,7 @@
#include <windows.h>
#include "common/platform.h"
-#if _WIN32_WINNT_WINBLUE
+#if _WIN32_WINNT_WINBLUE && WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP
#include <versionhelpers.h>
#endif
diff --git a/src/3rdparty/angle/src/third_party/trace_event/trace_event.h b/src/3rdparty/angle/src/third_party/trace_event/trace_event.h
index af59dcfcc3..3c85d22efa 100644
--- a/src/3rdparty/angle/src/third_party/trace_event/trace_event.h
+++ b/src/3rdparty/angle/src/third_party/trace_event/trace_event.h
@@ -459,7 +459,7 @@
// const unsigned char*
// TRACE_EVENT_API_GET_CATEGORY_ENABLED(const char* category_name)
#define TRACE_EVENT_API_GET_CATEGORY_ENABLED \
- gl::TraceGetTraceCategoryEnabledFlag
+ angle::GetTraceCategoryEnabledFlag
// Add a trace event to the platform tracing system.
// void TRACE_EVENT_API_ADD_TRACE_EVENT(
@@ -473,7 +473,7 @@
// const unsigned long long* arg_values,
// unsigned char flags)
#define TRACE_EVENT_API_ADD_TRACE_EVENT \
- gl::TraceAddTraceEvent
+ angle::AddTraceEvent
////////////////////////////////////////////////////////////////////////////////
@@ -690,45 +690,48 @@ static inline void setTraceValue(const std::string& arg,
// store pointers to the internal c_str and pass through to the tracing API, the
// arg values must live throughout these procedures.
-static inline void addTraceEvent(char phase,
- const unsigned char* categoryEnabled,
- const char* name,
- unsigned long long id,
- unsigned char flags) {
- TRACE_EVENT_API_ADD_TRACE_EVENT(
+static inline angle::Platform::TraceEventHandle addTraceEvent(
+ char phase,
+ const unsigned char* categoryEnabled,
+ const char* name,
+ unsigned long long id,
+ unsigned char flags) {
+ return TRACE_EVENT_API_ADD_TRACE_EVENT(
phase, categoryEnabled, name, id,
zeroNumArgs, 0, 0, 0,
flags);
}
template<class ARG1_TYPE>
-static inline void addTraceEvent(char phase,
- const unsigned char* categoryEnabled,
- const char* name,
- unsigned long long id,
- unsigned char flags,
- const char* arg1Name,
- const ARG1_TYPE& arg1Val) {
+static inline angle::Platform::TraceEventHandle addTraceEvent(
+ char phase,
+ const unsigned char* categoryEnabled,
+ const char* name,
+ unsigned long long id,
+ unsigned char flags,
+ const char* arg1Name,
+ const ARG1_TYPE& arg1Val) {
const int numArgs = 1;
unsigned char argTypes[1];
unsigned long long argValues[1];
setTraceValue(arg1Val, &argTypes[0], &argValues[0]);
- TRACE_EVENT_API_ADD_TRACE_EVENT(
+ return TRACE_EVENT_API_ADD_TRACE_EVENT(
phase, categoryEnabled, name, id,
numArgs, &arg1Name, argTypes, argValues,
flags);
}
template<class ARG1_TYPE, class ARG2_TYPE>
-static inline void addTraceEvent(char phase,
- const unsigned char* categoryEnabled,
- const char* name,
- unsigned long long id,
- unsigned char flags,
- const char* arg1Name,
- const ARG1_TYPE& arg1Val,
- const char* arg2Name,
- const ARG2_TYPE& arg2Val) {
+static inline angle::Platform::TraceEventHandle addTraceEvent(
+ char phase,
+ const unsigned char* categoryEnabled,
+ const char* name,
+ unsigned long long id,
+ unsigned char flags,
+ const char* arg1Name,
+ const ARG1_TYPE& arg1Val,
+ const char* arg2Name,
+ const ARG2_TYPE& arg2Val) {
const int numArgs = 2;
const char* argNames[2] = { arg1Name, arg2Name };
unsigned char argTypes[2];