From e12ba07322cd61c5cf50c25ed8d1f08f6b1ff879 Mon Sep 17 00:00:00 2001 From: Oliver Wolff Date: Thu, 24 Mar 2016 12:38:18 +0100 Subject: Update ANGLE to chromium/2651 Change-Id: I1cd32b780b1a0b913fab870e155ae1f4f9ac40d7 Reviewed-by: Maurice Kalinowski --- src/3rdparty/angle/src/common/BitSetIterator.h | 156 + src/3rdparty/angle/src/common/Float16ToFloat32.cpp | 2205 ++++++++++++ src/3rdparty/angle/src/common/Optional.h | 20 +- src/3rdparty/angle/src/common/angleutils.cpp | 7 + src/3rdparty/angle/src/common/angleutils.h | 7 +- src/3rdparty/angle/src/common/debug.cpp | 6 +- src/3rdparty/angle/src/common/debug.h | 37 +- src/3rdparty/angle/src/common/event_tracer.cpp | 52 +- src/3rdparty/angle/src/common/event_tracer.h | 26 +- src/3rdparty/angle/src/common/mathutil.cpp | 12 +- src/3rdparty/angle/src/common/mathutil.h | 206 +- src/3rdparty/angle/src/common/matrix_utils.h | 349 ++ src/3rdparty/angle/src/common/platform.h | 9 - src/3rdparty/angle/src/common/string_utils.cpp | 136 + src/3rdparty/angle/src/common/string_utils.h | 49 + src/3rdparty/angle/src/common/utilities.cpp | 311 +- src/3rdparty/angle/src/common/utilities.h | 40 + src/3rdparty/angle/src/common/version.h | 5 + .../src/compiler/preprocessor/DiagnosticsBase.cpp | 10 + .../src/compiler/preprocessor/DiagnosticsBase.h | 7 +- .../src/compiler/preprocessor/DirectiveParser.cpp | 236 +- .../src/compiler/preprocessor/DirectiveParser.h | 5 +- .../src/compiler/preprocessor/ExpressionParser.h | 14 +- .../src/compiler/preprocessor/ExpressionParser.y | 151 +- .../angle/src/compiler/preprocessor/Input.cpp | 66 +- .../angle/src/compiler/preprocessor/Input.h | 6 +- .../angle/src/compiler/preprocessor/Macro.cpp | 20 + .../angle/src/compiler/preprocessor/Macro.h | 2 + .../src/compiler/preprocessor/MacroExpander.cpp | 68 +- .../src/compiler/preprocessor/MacroExpander.h | 11 +- .../src/compiler/preprocessor/Preprocessor.cpp | 25 +- .../angle/src/compiler/preprocessor/Tokenizer.h | 2 +- .../angle/src/compiler/preprocessor/Tokenizer.l | 17 +- .../angle/src/compiler/preprocessor/numeric_lex.h | 10 + .../src/compiler/translator/ASTMetadataHLSL.cpp | 451 +++ .../src/compiler/translator/ASTMetadataHLSL.h | 58 + .../translator/ArrayReturnValueToOutParameter.cpp | 206 ++ .../translator/ArrayReturnValueToOutParameter.h | 16 + .../angle/src/compiler/translator/BaseTypes.h | 126 +- .../translator/BuiltInFunctionEmulator.cpp | 144 +- .../compiler/translator/BuiltInFunctionEmulator.h | 46 +- .../translator/BuiltInFunctionEmulatorGLSL.cpp | 162 +- .../translator/BuiltInFunctionEmulatorGLSL.h | 8 +- .../translator/BuiltInFunctionEmulatorHLSL.cpp | 47 +- .../angle/src/compiler/translator/Cache.cpp | 100 + src/3rdparty/angle/src/compiler/translator/Cache.h | 90 + .../angle/src/compiler/translator/CallDAG.cpp | 293 ++ .../angle/src/compiler/translator/CallDAG.h | 75 + .../angle/src/compiler/translator/CodeGen.cpp | 38 +- .../angle/src/compiler/translator/Common.h | 27 +- .../angle/src/compiler/translator/Compiler.cpp | 329 +- .../angle/src/compiler/translator/Compiler.h | 62 +- .../angle/src/compiler/translator/ConstantUnion.h | 60 +- .../angle/src/compiler/translator/Diagnostics.cpp | 7 +- .../angle/src/compiler/translator/Diagnostics.h | 8 +- .../src/compiler/translator/DirectiveHandler.cpp | 20 +- .../src/compiler/translator/DirectiveHandler.h | 31 +- .../src/compiler/translator/EmulatePrecision.cpp | 127 +- .../src/compiler/translator/EmulatePrecision.h | 26 +- .../src/compiler/translator/ExtensionBehavior.h | 6 + .../src/compiler/translator/ExtensionGLSL.cpp | 100 + .../angle/src/compiler/translator/ExtensionGLSL.h | 39 + .../src/compiler/translator/FlagStd140Structs.h | 10 +- .../src/compiler/translator/ForLoopUnroll.cpp | 29 +- .../angle/src/compiler/translator/ForLoopUnroll.h | 15 +- .../angle/src/compiler/translator/Initialize.cpp | 123 +- .../src/compiler/translator/InitializeDll.cpp | 4 + .../compiler/translator/InitializeParseContext.h | 2 +- .../compiler/translator/InitializeVariables.cpp | 9 +- .../src/compiler/translator/InitializeVariables.h | 17 +- .../angle/src/compiler/translator/IntermNode.cpp | 2392 ++++++++++--- .../angle/src/compiler/translator/IntermNode.h | 524 ++- .../src/compiler/translator/IntermTraverse.cpp | 660 +++- .../angle/src/compiler/translator/Intermediate.cpp | 189 +- .../angle/src/compiler/translator/Intermediate.h | 22 +- .../angle/src/compiler/translator/NodeSearch.h | 25 +- .../angle/src/compiler/translator/Operator.cpp | 6 + .../angle/src/compiler/translator/Operator.h | 7 +- .../angle/src/compiler/translator/OutputESSL.h | 3 +- .../angle/src/compiler/translator/OutputGLSL.cpp | 15 +- .../angle/src/compiler/translator/OutputGLSL.h | 6 +- .../src/compiler/translator/OutputGLSLBase.cpp | 322 +- .../angle/src/compiler/translator/OutputGLSLBase.h | 31 +- .../angle/src/compiler/translator/OutputHLSL.cpp | 1568 ++++++--- .../angle/src/compiler/translator/OutputHLSL.h | 59 +- .../angle/src/compiler/translator/ParseContext.cpp | 3544 +++++++++++++------- .../angle/src/compiler/translator/ParseContext.h | 473 ++- .../angle/src/compiler/translator/PoolAlloc.h | 25 +- .../compiler/translator/PruneEmptyDeclarations.cpp | 81 + .../compiler/translator/PruneEmptyDeclarations.h | 15 + .../translator/RecordConstantPrecision.cpp | 157 + .../compiler/translator/RecordConstantPrecision.h | 23 + .../compiler/translator/RegenerateStructNames.cpp | 2 +- .../compiler/translator/RegenerateStructNames.h | 7 +- .../compiler/translator/RemoveDynamicIndexing.cpp | 513 +++ .../compiler/translator/RemoveDynamicIndexing.h | 21 + .../angle/src/compiler/translator/RemovePow.cpp | 105 + .../angle/src/compiler/translator/RemovePow.h | 18 + .../angle/src/compiler/translator/RenameFunction.h | 2 +- .../src/compiler/translator/RewriteDoWhile.cpp | 163 + .../angle/src/compiler/translator/RewriteDoWhile.h | 16 + .../src/compiler/translator/RewriteElseBlocks.cpp | 58 +- .../src/compiler/translator/RewriteElseBlocks.h | 2 +- .../ScalarizeVecAndMatConstructorArgs.cpp | 22 +- .../translator/ScalarizeVecAndMatConstructorArgs.h | 5 +- .../angle/src/compiler/translator/SearchSymbol.cpp | 4 +- .../angle/src/compiler/translator/SearchSymbol.h | 2 +- .../translator/SeparateArrayInitialization.cpp | 92 + .../translator/SeparateArrayInitialization.h | 25 + .../compiler/translator/SeparateDeclarations.cpp | 77 + .../src/compiler/translator/SeparateDeclarations.h | 23 + .../SeparateExpressionsReturningArrays.cpp | 169 + .../SeparateExpressionsReturningArrays.h | 19 + .../angle/src/compiler/translator/ShaderLang.cpp | 67 +- .../angle/src/compiler/translator/ShaderVars.cpp | 74 +- .../angle/src/compiler/translator/SymbolTable.cpp | 80 +- .../angle/src/compiler/translator/SymbolTable.h | 173 +- .../src/compiler/translator/TranslatorESSL.cpp | 24 +- .../angle/src/compiler/translator/TranslatorESSL.h | 2 +- .../src/compiler/translator/TranslatorGLSL.cpp | 159 +- .../angle/src/compiler/translator/TranslatorGLSL.h | 4 +- .../src/compiler/translator/TranslatorHLSL.cpp | 36 +- .../angle/src/compiler/translator/TranslatorHLSL.h | 7 +- .../angle/src/compiler/translator/Types.cpp | 45 +- src/3rdparty/angle/src/compiler/translator/Types.h | 151 +- .../compiler/translator/UnfoldShortCircuitAST.cpp | 4 +- .../compiler/translator/UnfoldShortCircuitAST.h | 7 +- .../compiler/translator/UnfoldShortCircuitToIf.cpp | 368 ++ .../compiler/translator/UnfoldShortCircuitToIf.h | 18 + .../angle/src/compiler/translator/UniformHLSL.cpp | 128 +- .../angle/src/compiler/translator/UniformHLSL.h | 12 +- .../angle/src/compiler/translator/UtilsHLSL.cpp | 234 +- .../angle/src/compiler/translator/UtilsHLSL.h | 47 +- .../translator/ValidateGlobalInitializer.cpp | 112 + .../translator/ValidateGlobalInitializer.h | 16 + .../compiler/translator/ValidateLimitations.cpp | 73 +- .../src/compiler/translator/ValidateLimitations.h | 16 +- .../src/compiler/translator/ValidateOutputs.cpp | 98 +- .../src/compiler/translator/ValidateOutputs.h | 18 +- .../angle/src/compiler/translator/ValidateSwitch.h | 2 +- .../angle/src/compiler/translator/VariableInfo.cpp | 216 +- .../angle/src/compiler/translator/VariableInfo.h | 17 +- .../angle/src/compiler/translator/VersionGLSL.cpp | 59 +- .../angle/src/compiler/translator/VersionGLSL.h | 26 +- .../angle/src/compiler/translator/blocklayout.cpp | 5 +- .../angle/src/compiler/translator/blocklayout.h | 21 +- .../src/compiler/translator/blocklayoutHLSL.cpp | 12 +- .../translator/depgraph/DependencyGraph.cpp | 2 - .../compiler/translator/depgraph/DependencyGraph.h | 55 +- .../translator/depgraph/DependencyGraphBuilder.h | 10 +- .../translator/depgraph/DependencyGraphOutput.cpp | 3 +- .../angle/src/compiler/translator/glslang.h | 2 +- .../angle/src/compiler/translator/glslang.l | 97 +- .../angle/src/compiler/translator/glslang.y | 407 +-- .../angle/src/compiler/translator/intermOut.cpp | 61 +- .../timing/RestrictFragmentShaderTiming.cpp | 10 +- .../translator/timing/RestrictVertexShaderTiming.h | 3 +- .../angle/src/compiler/translator/util.cpp | 20 +- src/3rdparty/angle/src/compiler/translator/util.h | 9 +- src/3rdparty/angle/src/id/commit.h | 4 +- src/3rdparty/angle/src/libANGLE/AttributeMap.h | 8 +- src/3rdparty/angle/src/libANGLE/BinaryStream.h | 16 +- src/3rdparty/angle/src/libANGLE/Buffer.cpp | 91 +- src/3rdparty/angle/src/libANGLE/Buffer.h | 37 +- src/3rdparty/angle/src/libANGLE/Caps.cpp | 314 +- src/3rdparty/angle/src/libANGLE/Caps.h | 173 +- src/3rdparty/angle/src/libANGLE/Compiler.cpp | 114 +- src/3rdparty/angle/src/libANGLE/Compiler.h | 20 +- src/3rdparty/angle/src/libANGLE/Config.cpp | 8 +- src/3rdparty/angle/src/libANGLE/Config.h | 1 + src/3rdparty/angle/src/libANGLE/Context.cpp | 1333 ++++++-- src/3rdparty/angle/src/libANGLE/Context.h | 176 +- src/3rdparty/angle/src/libANGLE/Data.cpp | 55 +- src/3rdparty/angle/src/libANGLE/Data.h | 48 +- src/3rdparty/angle/src/libANGLE/Debug.cpp | 303 ++ src/3rdparty/angle/src/libANGLE/Debug.h | 120 + src/3rdparty/angle/src/libANGLE/Debug2.cpp | 303 ++ src/3rdparty/angle/src/libANGLE/Debug2.h | 120 + src/3rdparty/angle/src/libANGLE/Device.cpp | 130 + src/3rdparty/angle/src/libANGLE/Device.h | 58 + src/3rdparty/angle/src/libANGLE/Display.cpp | 426 ++- src/3rdparty/angle/src/libANGLE/Display.h | 28 +- src/3rdparty/angle/src/libANGLE/Error.cpp | 48 +- src/3rdparty/angle/src/libANGLE/Error.h | 37 +- src/3rdparty/angle/src/libANGLE/Error.inl | 66 +- src/3rdparty/angle/src/libANGLE/Fence.cpp | 46 +- src/3rdparty/angle/src/libANGLE/Fence.h | 22 +- .../angle/src/libANGLE/Float16ToFloat32.cpp | 2203 ------------ src/3rdparty/angle/src/libANGLE/Framebuffer.cpp | 619 ++-- src/3rdparty/angle/src/libANGLE/Framebuffer.h | 136 +- .../angle/src/libANGLE/FramebufferAttachment.cpp | 286 +- .../angle/src/libANGLE/FramebufferAttachment.h | 238 +- .../angle/src/libANGLE/HandleAllocator.cpp | 15 +- src/3rdparty/angle/src/libANGLE/HandleAllocator.h | 2 +- src/3rdparty/angle/src/libANGLE/Image.cpp | 192 ++ src/3rdparty/angle/src/libANGLE/Image.h | 91 + src/3rdparty/angle/src/libANGLE/ImageIndex.cpp | 23 +- src/3rdparty/angle/src/libANGLE/ImageIndex.h | 8 +- .../angle/src/libANGLE/IndexRangeCache.cpp | 113 + src/3rdparty/angle/src/libANGLE/IndexRangeCache.h | 60 + src/3rdparty/angle/src/libANGLE/Platform.cpp | 6 +- src/3rdparty/angle/src/libANGLE/Program.cpp | 1840 +++++++--- src/3rdparty/angle/src/libANGLE/Program.h | 336 +- src/3rdparty/angle/src/libANGLE/Query.cpp | 45 +- src/3rdparty/angle/src/libANGLE/Query.h | 18 +- src/3rdparty/angle/src/libANGLE/RefCountObject.h | 41 +- src/3rdparty/angle/src/libANGLE/Renderbuffer.cpp | 78 +- src/3rdparty/angle/src/libANGLE/Renderbuffer.h | 37 +- .../angle/src/libANGLE/ResourceManager.cpp | 8 +- src/3rdparty/angle/src/libANGLE/ResourceManager.h | 11 +- src/3rdparty/angle/src/libANGLE/Sampler.cpp | 151 +- src/3rdparty/angle/src/libANGLE/Sampler.h | 88 +- src/3rdparty/angle/src/libANGLE/Shader.cpp | 279 +- src/3rdparty/angle/src/libANGLE/Shader.h | 102 +- src/3rdparty/angle/src/libANGLE/State.cpp | 655 +++- src/3rdparty/angle/src/libANGLE/State.h | 175 +- src/3rdparty/angle/src/libANGLE/Surface.cpp | 137 +- src/3rdparty/angle/src/libANGLE/Surface.h | 49 +- src/3rdparty/angle/src/libANGLE/Texture.cpp | 502 ++- src/3rdparty/angle/src/libANGLE/Texture.h | 198 +- .../angle/src/libANGLE/TransformFeedback.cpp | 127 +- .../angle/src/libANGLE/TransformFeedback.h | 44 +- src/3rdparty/angle/src/libANGLE/Uniform.cpp | 136 +- src/3rdparty/angle/src/libANGLE/Uniform.h | 65 +- src/3rdparty/angle/src/libANGLE/Version.h | 33 + src/3rdparty/angle/src/libANGLE/Version.inl | 33 + src/3rdparty/angle/src/libANGLE/VertexArray.cpp | 115 +- src/3rdparty/angle/src/libANGLE/VertexArray.h | 83 +- .../angle/src/libANGLE/VertexAttribute.cpp | 37 +- src/3rdparty/angle/src/libANGLE/VertexAttribute.h | 73 +- .../angle/src/libANGLE/VertexAttribute.inl | 103 + src/3rdparty/angle/src/libANGLE/angletypes.cpp | 187 +- src/3rdparty/angle/src/libANGLE/angletypes.h | 181 +- src/3rdparty/angle/src/libANGLE/angletypes.inl | 78 + src/3rdparty/angle/src/libANGLE/features.h | 19 +- src/3rdparty/angle/src/libANGLE/formatutils.cpp | 978 +++++- src/3rdparty/angle/src/libANGLE/formatutils.h | 157 +- src/3rdparty/angle/src/libANGLE/histogram_macros.h | 107 + .../angle/src/libANGLE/queryconversions.cpp | 98 +- src/3rdparty/angle/src/libANGLE/queryconversions.h | 19 + .../angle/src/libANGLE/renderer/BufferImpl.h | 18 +- .../angle/src/libANGLE/renderer/BufferImpl_mock.h | 38 + .../angle/src/libANGLE/renderer/CompilerImpl.h | 4 + .../angle/src/libANGLE/renderer/DeviceImpl.cpp | 22 + .../angle/src/libANGLE/renderer/DeviceImpl.h | 37 + .../angle/src/libANGLE/renderer/DisplayImpl.cpp | 7 +- .../angle/src/libANGLE/renderer/DisplayImpl.h | 39 +- .../angle/src/libANGLE/renderer/FenceNVImpl.h | 6 +- .../angle/src/libANGLE/renderer/FenceSyncImpl.h | 2 +- .../angle/src/libANGLE/renderer/FramebufferImpl.h | 34 +- .../src/libANGLE/renderer/FramebufferImpl_mock.h | 72 + .../angle/src/libANGLE/renderer/ImageImpl.h | 32 + .../angle/src/libANGLE/renderer/ImageImpl_mock.h | 28 + .../angle/src/libANGLE/renderer/ImplFactory.h | 16 +- .../src/libANGLE/renderer/IndexRangeCache.cpp | 114 - .../angle/src/libANGLE/renderer/IndexRangeCache.h | 53 - .../angle/src/libANGLE/renderer/ProgramImpl.h | 90 +- .../angle/src/libANGLE/renderer/ProgramImpl_mock.h | 75 + .../angle/src/libANGLE/renderer/QueryImpl.h | 6 +- .../angle/src/libANGLE/renderer/RenderbufferImpl.h | 15 +- .../src/libANGLE/renderer/RenderbufferImpl_mock.h | 35 + .../angle/src/libANGLE/renderer/Renderer.cpp | 36 +- .../angle/src/libANGLE/renderer/Renderer.h | 70 +- .../angle/src/libANGLE/renderer/SamplerImpl.h | 25 + .../angle/src/libANGLE/renderer/ShaderImpl.h | 35 +- .../angle/src/libANGLE/renderer/SurfaceImpl.h | 10 +- .../angle/src/libANGLE/renderer/TextureImpl.h | 27 +- .../angle/src/libANGLE/renderer/TextureImpl_mock.h | 43 + .../src/libANGLE/renderer/TransformFeedbackImpl.h | 3 + .../libANGLE/renderer/TransformFeedbackImpl_mock.h | 37 + .../angle/src/libANGLE/renderer/VertexArrayImpl.h | 11 +- .../angle/src/libANGLE/renderer/d3d/BufferD3D.cpp | 194 +- .../angle/src/libANGLE/renderer/d3d/BufferD3D.h | 43 +- .../src/libANGLE/renderer/d3d/CompilerD3D.cpp | 122 +- .../angle/src/libANGLE/renderer/d3d/CompilerD3D.h | 27 +- .../angle/src/libANGLE/renderer/d3d/DeviceD3D.cpp | 102 + .../angle/src/libANGLE/renderer/d3d/DeviceD3D.h | 39 + .../angle/src/libANGLE/renderer/d3d/DisplayD3D.cpp | 195 +- .../angle/src/libANGLE/renderer/d3d/DisplayD3D.h | 39 +- .../src/libANGLE/renderer/d3d/DynamicHLSL.cpp | 1554 ++++----- .../angle/src/libANGLE/renderer/d3d/DynamicHLSL.h | 89 +- .../src/libANGLE/renderer/d3d/EGLImageD3D.cpp | 132 + .../angle/src/libANGLE/renderer/d3d/EGLImageD3D.h | 56 + .../src/libANGLE/renderer/d3d/FramebufferD3D.cpp | 271 +- .../src/libANGLE/renderer/d3d/FramebufferD3D.h | 66 +- .../src/libANGLE/renderer/d3d/HLSLCompiler.cpp | 163 +- .../angle/src/libANGLE/renderer/d3d/HLSLCompiler.h | 8 +- .../angle/src/libANGLE/renderer/d3d/ImageD3D.cpp | 21 +- .../angle/src/libANGLE/renderer/d3d/ImageD3D.h | 12 +- .../angle/src/libANGLE/renderer/d3d/IndexBuffer.h | 1 - .../src/libANGLE/renderer/d3d/IndexDataManager.cpp | 373 +- .../src/libANGLE/renderer/d3d/IndexDataManager.h | 29 +- .../angle/src/libANGLE/renderer/d3d/ProgramD3D.cpp | 2365 +++++++------ .../angle/src/libANGLE/renderer/d3d/ProgramD3D.h | 360 +- .../src/libANGLE/renderer/d3d/RenderTargetD3D.h | 3 +- .../src/libANGLE/renderer/d3d/RenderbufferD3D.cpp | 54 +- .../src/libANGLE/renderer/d3d/RenderbufferD3D.h | 18 +- .../src/libANGLE/renderer/d3d/RendererD3D.cpp | 421 ++- .../angle/src/libANGLE/renderer/d3d/RendererD3D.h | 231 +- .../angle/src/libANGLE/renderer/d3d/SamplerD3D.h | 25 + .../angle/src/libANGLE/renderer/d3d/ShaderD3D.cpp | 347 +- .../angle/src/libANGLE/renderer/d3d/ShaderD3D.h | 50 +- .../angle/src/libANGLE/renderer/d3d/SurfaceD3D.cpp | 187 +- .../angle/src/libANGLE/renderer/d3d/SurfaceD3D.h | 35 +- .../angle/src/libANGLE/renderer/d3d/SwapChainD3D.h | 7 +- .../angle/src/libANGLE/renderer/d3d/TextureD3D.cpp | 458 ++- .../angle/src/libANGLE/renderer/d3d/TextureD3D.h | 59 +- .../src/libANGLE/renderer/d3d/TextureStorage.h | 15 +- .../libANGLE/renderer/d3d/TransformFeedbackD3D.cpp | 8 + .../libANGLE/renderer/d3d/TransformFeedbackD3D.h | 11 +- .../src/libANGLE/renderer/d3d/VaryingPacking.cpp | 397 +++ .../src/libANGLE/renderer/d3d/VaryingPacking.h | 175 + .../src/libANGLE/renderer/d3d/VertexBuffer.cpp | 71 +- .../angle/src/libANGLE/renderer/d3d/VertexBuffer.h | 36 +- .../libANGLE/renderer/d3d/VertexDataManager.cpp | 374 ++- .../src/libANGLE/renderer/d3d/VertexDataManager.h | 57 +- .../src/libANGLE/renderer/d3d/WorkaroundsD3D.h | 66 + .../src/libANGLE/renderer/d3d/d3d11/Blit11.cpp | 926 +++-- .../angle/src/libANGLE/renderer/d3d/d3d11/Blit11.h | 145 +- .../src/libANGLE/renderer/d3d/d3d11/Buffer11.cpp | 875 +++-- .../src/libANGLE/renderer/d3d/d3d11/Buffer11.h | 52 +- .../src/libANGLE/renderer/d3d/d3d11/Clear11.cpp | 229 +- .../src/libANGLE/renderer/d3d/d3d11/Clear11.h | 39 +- .../renderer/d3d/d3d11/DebugAnnotator11.cpp | 83 +- .../libANGLE/renderer/d3d/d3d11/DebugAnnotator11.h | 4 +- .../src/libANGLE/renderer/d3d/d3d11/Fence11.cpp | 22 +- .../src/libANGLE/renderer/d3d/d3d11/Fence11.h | 18 +- .../libANGLE/renderer/d3d/d3d11/Framebuffer11.cpp | 294 +- .../libANGLE/renderer/d3d/d3d11/Framebuffer11.h | 15 +- .../src/libANGLE/renderer/d3d/d3d11/Image11.cpp | 336 +- .../src/libANGLE/renderer/d3d/d3d11/Image11.h | 17 +- .../libANGLE/renderer/d3d/d3d11/IndexBuffer11.cpp | 17 +- .../libANGLE/renderer/d3d/d3d11/IndexBuffer11.h | 2 - .../renderer/d3d/d3d11/InputLayoutCache.cpp | 693 ++-- .../libANGLE/renderer/d3d/d3d11/InputLayoutCache.h | 104 +- .../src/libANGLE/renderer/d3d/d3d11/NativeWindow.h | 17 +- .../renderer/d3d/d3d11/PixelTransfer11.cpp | 31 +- .../src/libANGLE/renderer/d3d/d3d11/Query11.cpp | 164 +- .../src/libANGLE/renderer/d3d/d3d11/Query11.h | 13 +- .../renderer/d3d/d3d11/RenderStateCache.cpp | 116 +- .../libANGLE/renderer/d3d/d3d11/RenderStateCache.h | 5 +- .../libANGLE/renderer/d3d/d3d11/RenderTarget11.cpp | 14 +- .../libANGLE/renderer/d3d/d3d11/RenderTarget11.h | 5 - .../src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp | 3108 ++++++++++------- .../src/libANGLE/renderer/d3d/d3d11/Renderer11.h | 285 +- .../renderer/d3d/d3d11/ShaderExecutable11.cpp | 14 +- .../renderer/d3d/d3d11/ShaderExecutable11.h | 4 - .../libANGLE/renderer/d3d/d3d11/StateManager11.cpp | 1040 ++++++ .../libANGLE/renderer/d3d/d3d11/StateManager11.h | 181 + .../libANGLE/renderer/d3d/d3d11/SwapChain11.cpp | 446 ++- .../src/libANGLE/renderer/d3d/d3d11/SwapChain11.h | 35 +- .../renderer/d3d/d3d11/TextureStorage11.cpp | 724 +++- .../libANGLE/renderer/d3d/d3d11/TextureStorage11.h | 74 +- .../angle/src/libANGLE/renderer/d3d/d3d11/Trim11.h | 2 + .../libANGLE/renderer/d3d/d3d11/VertexArray11.h | 15 +- .../libANGLE/renderer/d3d/d3d11/VertexBuffer11.cpp | 69 +- .../libANGLE/renderer/d3d/d3d11/VertexBuffer11.h | 11 +- .../src/libANGLE/renderer/d3d/d3d11/copyvertex.inl | 6 +- .../renderer/d3d/d3d11/dxgi_support_data.json | 1164 +++++++ .../renderer/d3d/d3d11/dxgi_support_table.cpp | 1846 ++++++++++ .../renderer/d3d/d3d11/dxgi_support_table.h | 44 + .../libANGLE/renderer/d3d/d3d11/formatutils11.cpp | 1501 ++++----- .../libANGLE/renderer/d3d/d3d11/formatutils11.h | 44 +- .../d3d/d3d11/gen_load_functions_table.cpp | 0 .../d3d11/internal_format_initializer_table.cpp | 170 + .../d3d/d3d11/internal_format_initializer_table.h | 31 + .../renderer/d3d/d3d11/load_functions_data.json | 1116 ++++++ .../renderer/d3d/d3d11/load_functions_table.h | 31 + .../d3d/d3d11/load_functions_table_autogen.cpp | 2098 ++++++++++++ .../renderer/d3d/d3d11/renderer11_utils.cpp | 744 +++- .../libANGLE/renderer/d3d/d3d11/renderer11_utils.h | 276 +- .../renderer/d3d/d3d11/swizzle_format_data.json | 77 + .../renderer/d3d/d3d11/swizzle_format_info.h | 51 + .../d3d/d3d11/swizzle_format_info_autogen.cpp | 203 ++ .../renderer/d3d/d3d11/texture_format_data.json | 692 ++++ .../renderer/d3d/d3d11/texture_format_table.h | 64 + .../d3d/d3d11/texture_format_table_autogen.cpp | 1791 ++++++++++ .../renderer/d3d/d3d11/win32/NativeWindow.cpp | 156 +- .../d3d/d3d11/winrt/CoreWindowNativeWindow.cpp | 75 +- .../d3d/d3d11/winrt/CoreWindowNativeWindow.h | 64 +- .../d3d/d3d11/winrt/InspectableNativeWindow.cpp | 160 +- .../d3d/d3d11/winrt/InspectableNativeWindow.h | 71 +- .../d3d/d3d11/winrt/SwapChainPanelNativeWindow.cpp | 232 +- .../d3d/d3d11/winrt/SwapChainPanelNativeWindow.h | 21 +- .../angle/src/libANGLE/renderer/d3d/d3d9/Blit9.cpp | 24 +- .../src/libANGLE/renderer/d3d/d3d9/Buffer9.cpp | 31 +- .../angle/src/libANGLE/renderer/d3d/d3d9/Buffer9.h | 10 +- .../libANGLE/renderer/d3d/d3d9/DebugAnnotator9.cpp | 8 +- .../libANGLE/renderer/d3d/d3d9/DebugAnnotator9.h | 4 +- .../src/libANGLE/renderer/d3d/d3d9/Fence9.cpp | 44 +- .../angle/src/libANGLE/renderer/d3d/d3d9/Fence9.h | 10 +- .../libANGLE/renderer/d3d/d3d9/Framebuffer9.cpp | 78 +- .../src/libANGLE/renderer/d3d/d3d9/Framebuffer9.h | 16 +- .../src/libANGLE/renderer/d3d/d3d9/Image9.cpp | 89 +- .../angle/src/libANGLE/renderer/d3d/d3d9/Image9.h | 13 +- .../libANGLE/renderer/d3d/d3d9/IndexBuffer9.cpp | 6 - .../src/libANGLE/renderer/d3d/d3d9/IndexBuffer9.h | 2 - .../src/libANGLE/renderer/d3d/d3d9/Query9.cpp | 36 +- .../angle/src/libANGLE/renderer/d3d/d3d9/Query9.h | 11 +- .../libANGLE/renderer/d3d/d3d9/RenderTarget9.cpp | 43 +- .../src/libANGLE/renderer/d3d/d3d9/RenderTarget9.h | 26 +- .../src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp | 1067 +++--- .../src/libANGLE/renderer/d3d/d3d9/Renderer9.h | 203 +- .../renderer/d3d/d3d9/ShaderExecutable9.cpp | 6 - .../libANGLE/renderer/d3d/d3d9/ShaderExecutable9.h | 2 - .../libANGLE/renderer/d3d/d3d9/StateManager9.cpp | 903 +++++ .../src/libANGLE/renderer/d3d/d3d9/StateManager9.h | 206 ++ .../src/libANGLE/renderer/d3d/d3d9/SwapChain9.cpp | 43 +- .../src/libANGLE/renderer/d3d/d3d9/SwapChain9.h | 12 +- .../libANGLE/renderer/d3d/d3d9/TextureStorage9.cpp | 272 +- .../libANGLE/renderer/d3d/d3d9/TextureStorage9.h | 44 +- .../src/libANGLE/renderer/d3d/d3d9/VertexArray9.h | 13 +- .../libANGLE/renderer/d3d/d3d9/VertexBuffer9.cpp | 58 +- .../src/libANGLE/renderer/d3d/d3d9/VertexBuffer9.h | 11 +- .../renderer/d3d/d3d9/VertexDeclarationCache.cpp | 56 +- .../renderer/d3d/d3d9/VertexDeclarationCache.h | 6 +- .../libANGLE/renderer/d3d/d3d9/formatutils9.cpp | 43 +- .../src/libANGLE/renderer/d3d/d3d9/formatutils9.h | 10 +- .../libANGLE/renderer/d3d/d3d9/renderer9_utils.cpp | 108 +- .../libANGLE/renderer/d3d/d3d9/renderer9_utils.h | 24 +- .../libANGLE/renderer/d3d/d3d9/vertexconversion.h | 5 +- .../src/libANGLE/renderer/d3d/formatutilsD3D.cpp | 4 +- .../angle/src/libANGLE/renderer/d3d/imageformats.h | 168 +- .../angle/src/libANGLE/renderer/d3d/loadimage.cpp | 105 +- .../angle/src/libANGLE/renderer/d3d/loadimage.h | 8 + .../src/libANGLE/renderer/d3d/loadimage_etc.cpp | 1435 ++++++++ .../src/libANGLE/renderer/d3d/loadimage_etc.h | 140 + src/3rdparty/angle/src/libANGLE/validationEGL.cpp | 566 +++- src/3rdparty/angle/src/libANGLE/validationEGL.h | 20 + src/3rdparty/angle/src/libANGLE/validationES.cpp | 1381 ++++++-- src/3rdparty/angle/src/libANGLE/validationES.h | 202 +- src/3rdparty/angle/src/libANGLE/validationES2.cpp | 922 ++++- src/3rdparty/angle/src/libANGLE/validationES2.h | 108 +- src/3rdparty/angle/src/libANGLE/validationES3.cpp | 718 +++- src/3rdparty/angle/src/libANGLE/validationES3.h | 226 +- src/3rdparty/angle/src/libEGL/libEGL.cpp | 41 + src/3rdparty/angle/src/libEGL/libEGL.def | 7 + src/3rdparty/angle/src/libEGL/libEGL_mingw32.def | 7 + src/3rdparty/angle/src/libEGL/libEGLd.def | 7 + src/3rdparty/angle/src/libEGL/libEGLd_mingw32.def | 7 + .../angle/src/libGLESv2/entry_points_egl.cpp | 687 +++- .../angle/src/libGLESv2/entry_points_egl_ext.cpp | 457 ++- .../angle/src/libGLESv2/entry_points_egl_ext.h | 18 + .../angle/src/libGLESv2/entry_points_gles_2_0.cpp | 715 ++-- .../src/libGLESv2/entry_points_gles_2_0_ext.cpp | 936 ++++-- .../src/libGLESv2/entry_points_gles_2_0_ext.h | 67 + .../angle/src/libGLESv2/entry_points_gles_3_0.cpp | 641 +--- src/3rdparty/angle/src/libGLESv2/global_state.cpp | 15 +- src/3rdparty/angle/src/libGLESv2/libGLESv2.cpp | 154 +- src/3rdparty/angle/src/libGLESv2/libGLESv2.def | 31 +- .../angle/src/libGLESv2/libGLESv2_mingw32.def | 32 +- src/3rdparty/angle/src/libGLESv2/libGLESv2d.def | 31 +- .../angle/src/libGLESv2/libGLESv2d_mingw32.def | 32 +- .../third_party/compiler/ArrayBoundsClamper.cpp | 5 +- .../src/third_party/murmurhash/MurmurHash3.cpp | 71 +- .../angle/src/third_party/murmurhash/MurmurHash3.h | 14 + .../src/third_party/systeminfo/SystemInfo.cpp | 2 +- .../src/third_party/trace_event/trace_event.h | 53 +- 458 files changed, 62860 insertions(+), 21310 deletions(-) create mode 100644 src/3rdparty/angle/src/common/BitSetIterator.h create mode 100644 src/3rdparty/angle/src/common/Float16ToFloat32.cpp create mode 100644 src/3rdparty/angle/src/common/matrix_utils.h create mode 100644 src/3rdparty/angle/src/common/string_utils.cpp create mode 100644 src/3rdparty/angle/src/common/string_utils.h create mode 100644 src/3rdparty/angle/src/compiler/translator/ASTMetadataHLSL.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/ASTMetadataHLSL.h create mode 100644 src/3rdparty/angle/src/compiler/translator/ArrayReturnValueToOutParameter.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/ArrayReturnValueToOutParameter.h create mode 100644 src/3rdparty/angle/src/compiler/translator/Cache.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/Cache.h create mode 100644 src/3rdparty/angle/src/compiler/translator/CallDAG.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/CallDAG.h create mode 100644 src/3rdparty/angle/src/compiler/translator/ExtensionGLSL.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/ExtensionGLSL.h create mode 100644 src/3rdparty/angle/src/compiler/translator/PruneEmptyDeclarations.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/PruneEmptyDeclarations.h create mode 100644 src/3rdparty/angle/src/compiler/translator/RecordConstantPrecision.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/RecordConstantPrecision.h create mode 100644 src/3rdparty/angle/src/compiler/translator/RemoveDynamicIndexing.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/RemoveDynamicIndexing.h create mode 100644 src/3rdparty/angle/src/compiler/translator/RemovePow.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/RemovePow.h create mode 100644 src/3rdparty/angle/src/compiler/translator/RewriteDoWhile.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/RewriteDoWhile.h create mode 100644 src/3rdparty/angle/src/compiler/translator/SeparateArrayInitialization.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/SeparateArrayInitialization.h create mode 100644 src/3rdparty/angle/src/compiler/translator/SeparateDeclarations.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/SeparateDeclarations.h create mode 100644 src/3rdparty/angle/src/compiler/translator/SeparateExpressionsReturningArrays.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/SeparateExpressionsReturningArrays.h create mode 100644 src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuitToIf.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuitToIf.h create mode 100644 src/3rdparty/angle/src/compiler/translator/ValidateGlobalInitializer.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/ValidateGlobalInitializer.h create mode 100644 src/3rdparty/angle/src/libANGLE/Debug.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/Debug.h create mode 100644 src/3rdparty/angle/src/libANGLE/Debug2.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/Debug2.h create mode 100644 src/3rdparty/angle/src/libANGLE/Device.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/Device.h delete mode 100644 src/3rdparty/angle/src/libANGLE/Float16ToFloat32.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/Image.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/Image.h create mode 100644 src/3rdparty/angle/src/libANGLE/IndexRangeCache.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/IndexRangeCache.h create mode 100644 src/3rdparty/angle/src/libANGLE/Version.h create mode 100644 src/3rdparty/angle/src/libANGLE/Version.inl create mode 100644 src/3rdparty/angle/src/libANGLE/VertexAttribute.inl create mode 100644 src/3rdparty/angle/src/libANGLE/angletypes.inl create mode 100644 src/3rdparty/angle/src/libANGLE/histogram_macros.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/BufferImpl_mock.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/DeviceImpl.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/DeviceImpl.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/FramebufferImpl_mock.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/ImageImpl.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/ImageImpl_mock.h delete mode 100644 src/3rdparty/angle/src/libANGLE/renderer/IndexRangeCache.cpp delete mode 100644 src/3rdparty/angle/src/libANGLE/renderer/IndexRangeCache.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/ProgramImpl_mock.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/RenderbufferImpl_mock.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/SamplerImpl.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/TextureImpl_mock.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/TransformFeedbackImpl_mock.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/DeviceD3D.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/DeviceD3D.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/EGLImageD3D.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/EGLImageD3D.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/SamplerD3D.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/VaryingPacking.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/VaryingPacking.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/WorkaroundsD3D.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/StateManager11.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/StateManager11.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/dxgi_support_data.json create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/dxgi_support_table.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/dxgi_support_table.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/gen_load_functions_table.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/internal_format_initializer_table.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/internal_format_initializer_table.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/load_functions_data.json create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/load_functions_table.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/load_functions_table_autogen.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/swizzle_format_data.json create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/swizzle_format_info.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/swizzle_format_info_autogen.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/texture_format_data.json create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/texture_format_table.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/texture_format_table_autogen.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/StateManager9.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/StateManager9.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimage_etc.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimage_etc.h (limited to 'src/3rdparty/angle/src') 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 + +#include + +#include "common/angleutils.h" +#include "common/debug.h" +#include "common/mathutil.h" +#include "common/platform.h" + +namespace angle +{ +template +class BitSetIterator final +{ + public: + BitSetIterator(const std::bitset &bitset); + BitSetIterator(const BitSetIterator &other); + BitSetIterator &operator=(const BitSetIterator &other); + + class Iterator final + { + public: + Iterator(const std::bitset &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 mBits; + unsigned long mCurrentBit; + unsigned long mOffset; + }; + + Iterator begin() const { return Iterator(mBits); } + Iterator end() const { return Iterator(std::bitset(0)); } + + private: + const std::bitset mBits; +}; + +template +BitSetIterator::BitSetIterator(const std::bitset &bitset) + : mBits(bitset) +{ +} + +template +BitSetIterator::BitSetIterator(const BitSetIterator &other) + : mBits(other.mBits) +{ +} + +template +BitSetIterator &BitSetIterator::operator=(const BitSetIterator &other) +{ + mBits = other.mBits; + return *this; +} + +template +BitSetIterator::Iterator::Iterator(const std::bitset &bits) + : mBits(bits), mCurrentBit(0), mOffset(0) +{ + if (bits.any()) + { + mCurrentBit = getNextBit(); + } + else + { + mOffset = static_cast(rx::roundUp(N, BitsPerWord)); + } +} + +template +typename BitSetIterator::Iterator &BitSetIterator::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(__builtin_ctzl(bits)); +#else +#error Please implement bit-scan-forward for your platform! +#endif +} + +template +bool BitSetIterator::Iterator::operator==(const Iterator &other) const +{ + return mOffset == other.mOffset && mBits == other.mBits; +} + +template +bool BitSetIterator::Iterator::operator!=(const Iterator &other) const +{ + return !(*this == other); +} + +template +unsigned long BitSetIterator::Iterator::getNextBit() +{ + static std::bitset wordMask(std::numeric_limits::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 +BitSetIterator IterateBitSet(const std::bitset &bitset) +{ + return BitSetIterator(bitset); +} + +} // angle + +#endif // COMMON_BITSETITERATOR_H_ diff --git a/src/3rdparty/angle/src/common/Float16ToFloat32.cpp b/src/3rdparty/angle/src/common/Float16ToFloat32.cpp new file mode 100644 index 0000000000..acd0d88b60 --- /dev/null +++ b/src/3rdparty/angle/src/common/Float16ToFloat32.cpp @@ -0,0 +1,2205 @@ +// +// Copyright (c) 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. +// + +// This file is automatically generated. + +#include "common/mathutil.h" + +namespace gl +{ + +const static unsigned g_mantissa[2048] = { + 0x00000000, + 0x33800000, + 0x34000000, + 0x34400000, + 0x34800000, + 0x34a00000, + 0x34c00000, + 0x34e00000, + 0x35000000, + 0x35100000, + 0x35200000, + 0x35300000, + 0x35400000, + 0x35500000, + 0x35600000, + 0x35700000, + 0x35800000, + 0x35880000, + 0x35900000, + 0x35980000, + 0x35a00000, + 0x35a80000, + 0x35b00000, + 0x35b80000, + 0x35c00000, + 0x35c80000, + 0x35d00000, + 0x35d80000, + 0x35e00000, + 0x35e80000, + 0x35f00000, + 0x35f80000, + 0x36000000, + 0x36040000, + 0x36080000, + 0x360c0000, + 0x36100000, + 0x36140000, + 0x36180000, + 0x361c0000, + 0x36200000, + 0x36240000, + 0x36280000, + 0x362c0000, + 0x36300000, + 0x36340000, + 0x36380000, + 0x363c0000, + 0x36400000, + 0x36440000, + 0x36480000, + 0x364c0000, + 0x36500000, + 0x36540000, + 0x36580000, + 0x365c0000, + 0x36600000, + 0x36640000, + 0x36680000, + 0x366c0000, + 0x36700000, + 0x36740000, + 0x36780000, + 0x367c0000, + 0x36800000, + 0x36820000, + 0x36840000, + 0x36860000, + 0x36880000, + 0x368a0000, + 0x368c0000, + 0x368e0000, + 0x36900000, + 0x36920000, + 0x36940000, + 0x36960000, + 0x36980000, + 0x369a0000, + 0x369c0000, + 0x369e0000, + 0x36a00000, + 0x36a20000, + 0x36a40000, + 0x36a60000, + 0x36a80000, + 0x36aa0000, + 0x36ac0000, + 0x36ae0000, + 0x36b00000, + 0x36b20000, + 0x36b40000, + 0x36b60000, + 0x36b80000, + 0x36ba0000, + 0x36bc0000, + 0x36be0000, + 0x36c00000, + 0x36c20000, + 0x36c40000, + 0x36c60000, + 0x36c80000, + 0x36ca0000, + 0x36cc0000, + 0x36ce0000, + 0x36d00000, + 0x36d20000, + 0x36d40000, + 0x36d60000, + 0x36d80000, + 0x36da0000, + 0x36dc0000, + 0x36de0000, + 0x36e00000, + 0x36e20000, + 0x36e40000, + 0x36e60000, + 0x36e80000, + 0x36ea0000, + 0x36ec0000, + 0x36ee0000, + 0x36f00000, + 0x36f20000, + 0x36f40000, + 0x36f60000, + 0x36f80000, + 0x36fa0000, + 0x36fc0000, + 0x36fe0000, + 0x37000000, + 0x37010000, + 0x37020000, + 0x37030000, + 0x37040000, + 0x37050000, + 0x37060000, + 0x37070000, + 0x37080000, + 0x37090000, + 0x370a0000, + 0x370b0000, + 0x370c0000, + 0x370d0000, + 0x370e0000, + 0x370f0000, + 0x37100000, + 0x37110000, + 0x37120000, + 0x37130000, + 0x37140000, + 0x37150000, + 0x37160000, + 0x37170000, + 0x37180000, + 0x37190000, + 0x371a0000, + 0x371b0000, + 0x371c0000, + 0x371d0000, + 0x371e0000, + 0x371f0000, + 0x37200000, + 0x37210000, + 0x37220000, + 0x37230000, + 0x37240000, + 0x37250000, + 0x37260000, + 0x37270000, + 0x37280000, + 0x37290000, + 0x372a0000, + 0x372b0000, + 0x372c0000, + 0x372d0000, + 0x372e0000, + 0x372f0000, + 0x37300000, + 0x37310000, + 0x37320000, + 0x37330000, + 0x37340000, + 0x37350000, + 0x37360000, + 0x37370000, + 0x37380000, + 0x37390000, + 0x373a0000, + 0x373b0000, + 0x373c0000, + 0x373d0000, + 0x373e0000, + 0x373f0000, + 0x37400000, + 0x37410000, + 0x37420000, + 0x37430000, + 0x37440000, + 0x37450000, + 0x37460000, + 0x37470000, + 0x37480000, + 0x37490000, + 0x374a0000, + 0x374b0000, + 0x374c0000, + 0x374d0000, + 0x374e0000, + 0x374f0000, + 0x37500000, + 0x37510000, + 0x37520000, + 0x37530000, + 0x37540000, + 0x37550000, + 0x37560000, + 0x37570000, + 0x37580000, + 0x37590000, + 0x375a0000, + 0x375b0000, + 0x375c0000, + 0x375d0000, + 0x375e0000, + 0x375f0000, + 0x37600000, + 0x37610000, + 0x37620000, + 0x37630000, + 0x37640000, + 0x37650000, + 0x37660000, + 0x37670000, + 0x37680000, + 0x37690000, + 0x376a0000, + 0x376b0000, + 0x376c0000, + 0x376d0000, + 0x376e0000, + 0x376f0000, + 0x37700000, + 0x37710000, + 0x37720000, + 0x37730000, + 0x37740000, + 0x37750000, + 0x37760000, + 0x37770000, + 0x37780000, + 0x37790000, + 0x377a0000, + 0x377b0000, + 0x377c0000, + 0x377d0000, + 0x377e0000, + 0x377f0000, + 0x37800000, + 0x37808000, + 0x37810000, + 0x37818000, + 0x37820000, + 0x37828000, + 0x37830000, + 0x37838000, + 0x37840000, + 0x37848000, + 0x37850000, + 0x37858000, + 0x37860000, + 0x37868000, + 0x37870000, + 0x37878000, + 0x37880000, + 0x37888000, + 0x37890000, + 0x37898000, + 0x378a0000, + 0x378a8000, + 0x378b0000, + 0x378b8000, + 0x378c0000, + 0x378c8000, + 0x378d0000, + 0x378d8000, + 0x378e0000, + 0x378e8000, + 0x378f0000, + 0x378f8000, + 0x37900000, + 0x37908000, + 0x37910000, + 0x37918000, + 0x37920000, + 0x37928000, + 0x37930000, + 0x37938000, + 0x37940000, + 0x37948000, + 0x37950000, + 0x37958000, + 0x37960000, + 0x37968000, + 0x37970000, + 0x37978000, + 0x37980000, + 0x37988000, + 0x37990000, + 0x37998000, + 0x379a0000, + 0x379a8000, + 0x379b0000, + 0x379b8000, + 0x379c0000, + 0x379c8000, + 0x379d0000, + 0x379d8000, + 0x379e0000, + 0x379e8000, + 0x379f0000, + 0x379f8000, + 0x37a00000, + 0x37a08000, + 0x37a10000, + 0x37a18000, + 0x37a20000, + 0x37a28000, + 0x37a30000, + 0x37a38000, + 0x37a40000, + 0x37a48000, + 0x37a50000, + 0x37a58000, + 0x37a60000, + 0x37a68000, + 0x37a70000, + 0x37a78000, + 0x37a80000, + 0x37a88000, + 0x37a90000, + 0x37a98000, + 0x37aa0000, + 0x37aa8000, + 0x37ab0000, + 0x37ab8000, + 0x37ac0000, + 0x37ac8000, + 0x37ad0000, + 0x37ad8000, + 0x37ae0000, + 0x37ae8000, + 0x37af0000, + 0x37af8000, + 0x37b00000, + 0x37b08000, + 0x37b10000, + 0x37b18000, + 0x37b20000, + 0x37b28000, + 0x37b30000, + 0x37b38000, + 0x37b40000, + 0x37b48000, + 0x37b50000, + 0x37b58000, + 0x37b60000, + 0x37b68000, + 0x37b70000, + 0x37b78000, + 0x37b80000, + 0x37b88000, + 0x37b90000, + 0x37b98000, + 0x37ba0000, + 0x37ba8000, + 0x37bb0000, + 0x37bb8000, + 0x37bc0000, + 0x37bc8000, + 0x37bd0000, + 0x37bd8000, + 0x37be0000, + 0x37be8000, + 0x37bf0000, + 0x37bf8000, + 0x37c00000, + 0x37c08000, + 0x37c10000, + 0x37c18000, + 0x37c20000, + 0x37c28000, + 0x37c30000, + 0x37c38000, + 0x37c40000, + 0x37c48000, + 0x37c50000, + 0x37c58000, + 0x37c60000, + 0x37c68000, + 0x37c70000, + 0x37c78000, + 0x37c80000, + 0x37c88000, + 0x37c90000, + 0x37c98000, + 0x37ca0000, + 0x37ca8000, + 0x37cb0000, + 0x37cb8000, + 0x37cc0000, + 0x37cc8000, + 0x37cd0000, + 0x37cd8000, + 0x37ce0000, + 0x37ce8000, + 0x37cf0000, + 0x37cf8000, + 0x37d00000, + 0x37d08000, + 0x37d10000, + 0x37d18000, + 0x37d20000, + 0x37d28000, + 0x37d30000, + 0x37d38000, + 0x37d40000, + 0x37d48000, + 0x37d50000, + 0x37d58000, + 0x37d60000, + 0x37d68000, + 0x37d70000, + 0x37d78000, + 0x37d80000, + 0x37d88000, + 0x37d90000, + 0x37d98000, + 0x37da0000, + 0x37da8000, + 0x37db0000, + 0x37db8000, + 0x37dc0000, + 0x37dc8000, + 0x37dd0000, + 0x37dd8000, + 0x37de0000, + 0x37de8000, + 0x37df0000, + 0x37df8000, + 0x37e00000, + 0x37e08000, + 0x37e10000, + 0x37e18000, + 0x37e20000, + 0x37e28000, + 0x37e30000, + 0x37e38000, + 0x37e40000, + 0x37e48000, + 0x37e50000, + 0x37e58000, + 0x37e60000, + 0x37e68000, + 0x37e70000, + 0x37e78000, + 0x37e80000, + 0x37e88000, + 0x37e90000, + 0x37e98000, + 0x37ea0000, + 0x37ea8000, + 0x37eb0000, + 0x37eb8000, + 0x37ec0000, + 0x37ec8000, + 0x37ed0000, + 0x37ed8000, + 0x37ee0000, + 0x37ee8000, + 0x37ef0000, + 0x37ef8000, + 0x37f00000, + 0x37f08000, + 0x37f10000, + 0x37f18000, + 0x37f20000, + 0x37f28000, + 0x37f30000, + 0x37f38000, + 0x37f40000, + 0x37f48000, + 0x37f50000, + 0x37f58000, + 0x37f60000, + 0x37f68000, + 0x37f70000, + 0x37f78000, + 0x37f80000, + 0x37f88000, + 0x37f90000, + 0x37f98000, + 0x37fa0000, + 0x37fa8000, + 0x37fb0000, + 0x37fb8000, + 0x37fc0000, + 0x37fc8000, + 0x37fd0000, + 0x37fd8000, + 0x37fe0000, + 0x37fe8000, + 0x37ff0000, + 0x37ff8000, + 0x38000000, + 0x38004000, + 0x38008000, + 0x3800c000, + 0x38010000, + 0x38014000, + 0x38018000, + 0x3801c000, + 0x38020000, + 0x38024000, + 0x38028000, + 0x3802c000, + 0x38030000, + 0x38034000, + 0x38038000, + 0x3803c000, + 0x38040000, + 0x38044000, + 0x38048000, + 0x3804c000, + 0x38050000, + 0x38054000, + 0x38058000, + 0x3805c000, + 0x38060000, + 0x38064000, + 0x38068000, + 0x3806c000, + 0x38070000, + 0x38074000, + 0x38078000, + 0x3807c000, + 0x38080000, + 0x38084000, + 0x38088000, + 0x3808c000, + 0x38090000, + 0x38094000, + 0x38098000, + 0x3809c000, + 0x380a0000, + 0x380a4000, + 0x380a8000, + 0x380ac000, + 0x380b0000, + 0x380b4000, + 0x380b8000, + 0x380bc000, + 0x380c0000, + 0x380c4000, + 0x380c8000, + 0x380cc000, + 0x380d0000, + 0x380d4000, + 0x380d8000, + 0x380dc000, + 0x380e0000, + 0x380e4000, + 0x380e8000, + 0x380ec000, + 0x380f0000, + 0x380f4000, + 0x380f8000, + 0x380fc000, + 0x38100000, + 0x38104000, + 0x38108000, + 0x3810c000, + 0x38110000, + 0x38114000, + 0x38118000, + 0x3811c000, + 0x38120000, + 0x38124000, + 0x38128000, + 0x3812c000, + 0x38130000, + 0x38134000, + 0x38138000, + 0x3813c000, + 0x38140000, + 0x38144000, + 0x38148000, + 0x3814c000, + 0x38150000, + 0x38154000, + 0x38158000, + 0x3815c000, + 0x38160000, + 0x38164000, + 0x38168000, + 0x3816c000, + 0x38170000, + 0x38174000, + 0x38178000, + 0x3817c000, + 0x38180000, + 0x38184000, + 0x38188000, + 0x3818c000, + 0x38190000, + 0x38194000, + 0x38198000, + 0x3819c000, + 0x381a0000, + 0x381a4000, + 0x381a8000, + 0x381ac000, + 0x381b0000, + 0x381b4000, + 0x381b8000, + 0x381bc000, + 0x381c0000, + 0x381c4000, + 0x381c8000, + 0x381cc000, + 0x381d0000, + 0x381d4000, + 0x381d8000, + 0x381dc000, + 0x381e0000, + 0x381e4000, + 0x381e8000, + 0x381ec000, + 0x381f0000, + 0x381f4000, + 0x381f8000, + 0x381fc000, + 0x38200000, + 0x38204000, + 0x38208000, + 0x3820c000, + 0x38210000, + 0x38214000, + 0x38218000, + 0x3821c000, + 0x38220000, + 0x38224000, + 0x38228000, + 0x3822c000, + 0x38230000, + 0x38234000, + 0x38238000, + 0x3823c000, + 0x38240000, + 0x38244000, + 0x38248000, + 0x3824c000, + 0x38250000, + 0x38254000, + 0x38258000, + 0x3825c000, + 0x38260000, + 0x38264000, + 0x38268000, + 0x3826c000, + 0x38270000, + 0x38274000, + 0x38278000, + 0x3827c000, + 0x38280000, + 0x38284000, + 0x38288000, + 0x3828c000, + 0x38290000, + 0x38294000, + 0x38298000, + 0x3829c000, + 0x382a0000, + 0x382a4000, + 0x382a8000, + 0x382ac000, + 0x382b0000, + 0x382b4000, + 0x382b8000, + 0x382bc000, + 0x382c0000, + 0x382c4000, + 0x382c8000, + 0x382cc000, + 0x382d0000, + 0x382d4000, + 0x382d8000, + 0x382dc000, + 0x382e0000, + 0x382e4000, + 0x382e8000, + 0x382ec000, + 0x382f0000, + 0x382f4000, + 0x382f8000, + 0x382fc000, + 0x38300000, + 0x38304000, + 0x38308000, + 0x3830c000, + 0x38310000, + 0x38314000, + 0x38318000, + 0x3831c000, + 0x38320000, + 0x38324000, + 0x38328000, + 0x3832c000, + 0x38330000, + 0x38334000, + 0x38338000, + 0x3833c000, + 0x38340000, + 0x38344000, + 0x38348000, + 0x3834c000, + 0x38350000, + 0x38354000, + 0x38358000, + 0x3835c000, + 0x38360000, + 0x38364000, + 0x38368000, + 0x3836c000, + 0x38370000, + 0x38374000, + 0x38378000, + 0x3837c000, + 0x38380000, + 0x38384000, + 0x38388000, + 0x3838c000, + 0x38390000, + 0x38394000, + 0x38398000, + 0x3839c000, + 0x383a0000, + 0x383a4000, + 0x383a8000, + 0x383ac000, + 0x383b0000, + 0x383b4000, + 0x383b8000, + 0x383bc000, + 0x383c0000, + 0x383c4000, + 0x383c8000, + 0x383cc000, + 0x383d0000, + 0x383d4000, + 0x383d8000, + 0x383dc000, + 0x383e0000, + 0x383e4000, + 0x383e8000, + 0x383ec000, + 0x383f0000, + 0x383f4000, + 0x383f8000, + 0x383fc000, + 0x38400000, + 0x38404000, + 0x38408000, + 0x3840c000, + 0x38410000, + 0x38414000, + 0x38418000, + 0x3841c000, + 0x38420000, + 0x38424000, + 0x38428000, + 0x3842c000, + 0x38430000, + 0x38434000, + 0x38438000, + 0x3843c000, + 0x38440000, + 0x38444000, + 0x38448000, + 0x3844c000, + 0x38450000, + 0x38454000, + 0x38458000, + 0x3845c000, + 0x38460000, + 0x38464000, + 0x38468000, + 0x3846c000, + 0x38470000, + 0x38474000, + 0x38478000, + 0x3847c000, + 0x38480000, + 0x38484000, + 0x38488000, + 0x3848c000, + 0x38490000, + 0x38494000, + 0x38498000, + 0x3849c000, + 0x384a0000, + 0x384a4000, + 0x384a8000, + 0x384ac000, + 0x384b0000, + 0x384b4000, + 0x384b8000, + 0x384bc000, + 0x384c0000, + 0x384c4000, + 0x384c8000, + 0x384cc000, + 0x384d0000, + 0x384d4000, + 0x384d8000, + 0x384dc000, + 0x384e0000, + 0x384e4000, + 0x384e8000, + 0x384ec000, + 0x384f0000, + 0x384f4000, + 0x384f8000, + 0x384fc000, + 0x38500000, + 0x38504000, + 0x38508000, + 0x3850c000, + 0x38510000, + 0x38514000, + 0x38518000, + 0x3851c000, + 0x38520000, + 0x38524000, + 0x38528000, + 0x3852c000, + 0x38530000, + 0x38534000, + 0x38538000, + 0x3853c000, + 0x38540000, + 0x38544000, + 0x38548000, + 0x3854c000, + 0x38550000, + 0x38554000, + 0x38558000, + 0x3855c000, + 0x38560000, + 0x38564000, + 0x38568000, + 0x3856c000, + 0x38570000, + 0x38574000, + 0x38578000, + 0x3857c000, + 0x38580000, + 0x38584000, + 0x38588000, + 0x3858c000, + 0x38590000, + 0x38594000, + 0x38598000, + 0x3859c000, + 0x385a0000, + 0x385a4000, + 0x385a8000, + 0x385ac000, + 0x385b0000, + 0x385b4000, + 0x385b8000, + 0x385bc000, + 0x385c0000, + 0x385c4000, + 0x385c8000, + 0x385cc000, + 0x385d0000, + 0x385d4000, + 0x385d8000, + 0x385dc000, + 0x385e0000, + 0x385e4000, + 0x385e8000, + 0x385ec000, + 0x385f0000, + 0x385f4000, + 0x385f8000, + 0x385fc000, + 0x38600000, + 0x38604000, + 0x38608000, + 0x3860c000, + 0x38610000, + 0x38614000, + 0x38618000, + 0x3861c000, + 0x38620000, + 0x38624000, + 0x38628000, + 0x3862c000, + 0x38630000, + 0x38634000, + 0x38638000, + 0x3863c000, + 0x38640000, + 0x38644000, + 0x38648000, + 0x3864c000, + 0x38650000, + 0x38654000, + 0x38658000, + 0x3865c000, + 0x38660000, + 0x38664000, + 0x38668000, + 0x3866c000, + 0x38670000, + 0x38674000, + 0x38678000, + 0x3867c000, + 0x38680000, + 0x38684000, + 0x38688000, + 0x3868c000, + 0x38690000, + 0x38694000, + 0x38698000, + 0x3869c000, + 0x386a0000, + 0x386a4000, + 0x386a8000, + 0x386ac000, + 0x386b0000, + 0x386b4000, + 0x386b8000, + 0x386bc000, + 0x386c0000, + 0x386c4000, + 0x386c8000, + 0x386cc000, + 0x386d0000, + 0x386d4000, + 0x386d8000, + 0x386dc000, + 0x386e0000, + 0x386e4000, + 0x386e8000, + 0x386ec000, + 0x386f0000, + 0x386f4000, + 0x386f8000, + 0x386fc000, + 0x38700000, + 0x38704000, + 0x38708000, + 0x3870c000, + 0x38710000, + 0x38714000, + 0x38718000, + 0x3871c000, + 0x38720000, + 0x38724000, + 0x38728000, + 0x3872c000, + 0x38730000, + 0x38734000, + 0x38738000, + 0x3873c000, + 0x38740000, + 0x38744000, + 0x38748000, + 0x3874c000, + 0x38750000, + 0x38754000, + 0x38758000, + 0x3875c000, + 0x38760000, + 0x38764000, + 0x38768000, + 0x3876c000, + 0x38770000, + 0x38774000, + 0x38778000, + 0x3877c000, + 0x38780000, + 0x38784000, + 0x38788000, + 0x3878c000, + 0x38790000, + 0x38794000, + 0x38798000, + 0x3879c000, + 0x387a0000, + 0x387a4000, + 0x387a8000, + 0x387ac000, + 0x387b0000, + 0x387b4000, + 0x387b8000, + 0x387bc000, + 0x387c0000, + 0x387c4000, + 0x387c8000, + 0x387cc000, + 0x387d0000, + 0x387d4000, + 0x387d8000, + 0x387dc000, + 0x387e0000, + 0x387e4000, + 0x387e8000, + 0x387ec000, + 0x387f0000, + 0x387f4000, + 0x387f8000, + 0x387fc000, + 0x38000000, + 0x38002000, + 0x38004000, + 0x38006000, + 0x38008000, + 0x3800a000, + 0x3800c000, + 0x3800e000, + 0x38010000, + 0x38012000, + 0x38014000, + 0x38016000, + 0x38018000, + 0x3801a000, + 0x3801c000, + 0x3801e000, + 0x38020000, + 0x38022000, + 0x38024000, + 0x38026000, + 0x38028000, + 0x3802a000, + 0x3802c000, + 0x3802e000, + 0x38030000, + 0x38032000, + 0x38034000, + 0x38036000, + 0x38038000, + 0x3803a000, + 0x3803c000, + 0x3803e000, + 0x38040000, + 0x38042000, + 0x38044000, + 0x38046000, + 0x38048000, + 0x3804a000, + 0x3804c000, + 0x3804e000, + 0x38050000, + 0x38052000, + 0x38054000, + 0x38056000, + 0x38058000, + 0x3805a000, + 0x3805c000, + 0x3805e000, + 0x38060000, + 0x38062000, + 0x38064000, + 0x38066000, + 0x38068000, + 0x3806a000, + 0x3806c000, + 0x3806e000, + 0x38070000, + 0x38072000, + 0x38074000, + 0x38076000, + 0x38078000, + 0x3807a000, + 0x3807c000, + 0x3807e000, + 0x38080000, + 0x38082000, + 0x38084000, + 0x38086000, + 0x38088000, + 0x3808a000, + 0x3808c000, + 0x3808e000, + 0x38090000, + 0x38092000, + 0x38094000, + 0x38096000, + 0x38098000, + 0x3809a000, + 0x3809c000, + 0x3809e000, + 0x380a0000, + 0x380a2000, + 0x380a4000, + 0x380a6000, + 0x380a8000, + 0x380aa000, + 0x380ac000, + 0x380ae000, + 0x380b0000, + 0x380b2000, + 0x380b4000, + 0x380b6000, + 0x380b8000, + 0x380ba000, + 0x380bc000, + 0x380be000, + 0x380c0000, + 0x380c2000, + 0x380c4000, + 0x380c6000, + 0x380c8000, + 0x380ca000, + 0x380cc000, + 0x380ce000, + 0x380d0000, + 0x380d2000, + 0x380d4000, + 0x380d6000, + 0x380d8000, + 0x380da000, + 0x380dc000, + 0x380de000, + 0x380e0000, + 0x380e2000, + 0x380e4000, + 0x380e6000, + 0x380e8000, + 0x380ea000, + 0x380ec000, + 0x380ee000, + 0x380f0000, + 0x380f2000, + 0x380f4000, + 0x380f6000, + 0x380f8000, + 0x380fa000, + 0x380fc000, + 0x380fe000, + 0x38100000, + 0x38102000, + 0x38104000, + 0x38106000, + 0x38108000, + 0x3810a000, + 0x3810c000, + 0x3810e000, + 0x38110000, + 0x38112000, + 0x38114000, + 0x38116000, + 0x38118000, + 0x3811a000, + 0x3811c000, + 0x3811e000, + 0x38120000, + 0x38122000, + 0x38124000, + 0x38126000, + 0x38128000, + 0x3812a000, + 0x3812c000, + 0x3812e000, + 0x38130000, + 0x38132000, + 0x38134000, + 0x38136000, + 0x38138000, + 0x3813a000, + 0x3813c000, + 0x3813e000, + 0x38140000, + 0x38142000, + 0x38144000, + 0x38146000, + 0x38148000, + 0x3814a000, + 0x3814c000, + 0x3814e000, + 0x38150000, + 0x38152000, + 0x38154000, + 0x38156000, + 0x38158000, + 0x3815a000, + 0x3815c000, + 0x3815e000, + 0x38160000, + 0x38162000, + 0x38164000, + 0x38166000, + 0x38168000, + 0x3816a000, + 0x3816c000, + 0x3816e000, + 0x38170000, + 0x38172000, + 0x38174000, + 0x38176000, + 0x38178000, + 0x3817a000, + 0x3817c000, + 0x3817e000, + 0x38180000, + 0x38182000, + 0x38184000, + 0x38186000, + 0x38188000, + 0x3818a000, + 0x3818c000, + 0x3818e000, + 0x38190000, + 0x38192000, + 0x38194000, + 0x38196000, + 0x38198000, + 0x3819a000, + 0x3819c000, + 0x3819e000, + 0x381a0000, + 0x381a2000, + 0x381a4000, + 0x381a6000, + 0x381a8000, + 0x381aa000, + 0x381ac000, + 0x381ae000, + 0x381b0000, + 0x381b2000, + 0x381b4000, + 0x381b6000, + 0x381b8000, + 0x381ba000, + 0x381bc000, + 0x381be000, + 0x381c0000, + 0x381c2000, + 0x381c4000, + 0x381c6000, + 0x381c8000, + 0x381ca000, + 0x381cc000, + 0x381ce000, + 0x381d0000, + 0x381d2000, + 0x381d4000, + 0x381d6000, + 0x381d8000, + 0x381da000, + 0x381dc000, + 0x381de000, + 0x381e0000, + 0x381e2000, + 0x381e4000, + 0x381e6000, + 0x381e8000, + 0x381ea000, + 0x381ec000, + 0x381ee000, + 0x381f0000, + 0x381f2000, + 0x381f4000, + 0x381f6000, + 0x381f8000, + 0x381fa000, + 0x381fc000, + 0x381fe000, + 0x38200000, + 0x38202000, + 0x38204000, + 0x38206000, + 0x38208000, + 0x3820a000, + 0x3820c000, + 0x3820e000, + 0x38210000, + 0x38212000, + 0x38214000, + 0x38216000, + 0x38218000, + 0x3821a000, + 0x3821c000, + 0x3821e000, + 0x38220000, + 0x38222000, + 0x38224000, + 0x38226000, + 0x38228000, + 0x3822a000, + 0x3822c000, + 0x3822e000, + 0x38230000, + 0x38232000, + 0x38234000, + 0x38236000, + 0x38238000, + 0x3823a000, + 0x3823c000, + 0x3823e000, + 0x38240000, + 0x38242000, + 0x38244000, + 0x38246000, + 0x38248000, + 0x3824a000, + 0x3824c000, + 0x3824e000, + 0x38250000, + 0x38252000, + 0x38254000, + 0x38256000, + 0x38258000, + 0x3825a000, + 0x3825c000, + 0x3825e000, + 0x38260000, + 0x38262000, + 0x38264000, + 0x38266000, + 0x38268000, + 0x3826a000, + 0x3826c000, + 0x3826e000, + 0x38270000, + 0x38272000, + 0x38274000, + 0x38276000, + 0x38278000, + 0x3827a000, + 0x3827c000, + 0x3827e000, + 0x38280000, + 0x38282000, + 0x38284000, + 0x38286000, + 0x38288000, + 0x3828a000, + 0x3828c000, + 0x3828e000, + 0x38290000, + 0x38292000, + 0x38294000, + 0x38296000, + 0x38298000, + 0x3829a000, + 0x3829c000, + 0x3829e000, + 0x382a0000, + 0x382a2000, + 0x382a4000, + 0x382a6000, + 0x382a8000, + 0x382aa000, + 0x382ac000, + 0x382ae000, + 0x382b0000, + 0x382b2000, + 0x382b4000, + 0x382b6000, + 0x382b8000, + 0x382ba000, + 0x382bc000, + 0x382be000, + 0x382c0000, + 0x382c2000, + 0x382c4000, + 0x382c6000, + 0x382c8000, + 0x382ca000, + 0x382cc000, + 0x382ce000, + 0x382d0000, + 0x382d2000, + 0x382d4000, + 0x382d6000, + 0x382d8000, + 0x382da000, + 0x382dc000, + 0x382de000, + 0x382e0000, + 0x382e2000, + 0x382e4000, + 0x382e6000, + 0x382e8000, + 0x382ea000, + 0x382ec000, + 0x382ee000, + 0x382f0000, + 0x382f2000, + 0x382f4000, + 0x382f6000, + 0x382f8000, + 0x382fa000, + 0x382fc000, + 0x382fe000, + 0x38300000, + 0x38302000, + 0x38304000, + 0x38306000, + 0x38308000, + 0x3830a000, + 0x3830c000, + 0x3830e000, + 0x38310000, + 0x38312000, + 0x38314000, + 0x38316000, + 0x38318000, + 0x3831a000, + 0x3831c000, + 0x3831e000, + 0x38320000, + 0x38322000, + 0x38324000, + 0x38326000, + 0x38328000, + 0x3832a000, + 0x3832c000, + 0x3832e000, + 0x38330000, + 0x38332000, + 0x38334000, + 0x38336000, + 0x38338000, + 0x3833a000, + 0x3833c000, + 0x3833e000, + 0x38340000, + 0x38342000, + 0x38344000, + 0x38346000, + 0x38348000, + 0x3834a000, + 0x3834c000, + 0x3834e000, + 0x38350000, + 0x38352000, + 0x38354000, + 0x38356000, + 0x38358000, + 0x3835a000, + 0x3835c000, + 0x3835e000, + 0x38360000, + 0x38362000, + 0x38364000, + 0x38366000, + 0x38368000, + 0x3836a000, + 0x3836c000, + 0x3836e000, + 0x38370000, + 0x38372000, + 0x38374000, + 0x38376000, + 0x38378000, + 0x3837a000, + 0x3837c000, + 0x3837e000, + 0x38380000, + 0x38382000, + 0x38384000, + 0x38386000, + 0x38388000, + 0x3838a000, + 0x3838c000, + 0x3838e000, + 0x38390000, + 0x38392000, + 0x38394000, + 0x38396000, + 0x38398000, + 0x3839a000, + 0x3839c000, + 0x3839e000, + 0x383a0000, + 0x383a2000, + 0x383a4000, + 0x383a6000, + 0x383a8000, + 0x383aa000, + 0x383ac000, + 0x383ae000, + 0x383b0000, + 0x383b2000, + 0x383b4000, + 0x383b6000, + 0x383b8000, + 0x383ba000, + 0x383bc000, + 0x383be000, + 0x383c0000, + 0x383c2000, + 0x383c4000, + 0x383c6000, + 0x383c8000, + 0x383ca000, + 0x383cc000, + 0x383ce000, + 0x383d0000, + 0x383d2000, + 0x383d4000, + 0x383d6000, + 0x383d8000, + 0x383da000, + 0x383dc000, + 0x383de000, + 0x383e0000, + 0x383e2000, + 0x383e4000, + 0x383e6000, + 0x383e8000, + 0x383ea000, + 0x383ec000, + 0x383ee000, + 0x383f0000, + 0x383f2000, + 0x383f4000, + 0x383f6000, + 0x383f8000, + 0x383fa000, + 0x383fc000, + 0x383fe000, + 0x38400000, + 0x38402000, + 0x38404000, + 0x38406000, + 0x38408000, + 0x3840a000, + 0x3840c000, + 0x3840e000, + 0x38410000, + 0x38412000, + 0x38414000, + 0x38416000, + 0x38418000, + 0x3841a000, + 0x3841c000, + 0x3841e000, + 0x38420000, + 0x38422000, + 0x38424000, + 0x38426000, + 0x38428000, + 0x3842a000, + 0x3842c000, + 0x3842e000, + 0x38430000, + 0x38432000, + 0x38434000, + 0x38436000, + 0x38438000, + 0x3843a000, + 0x3843c000, + 0x3843e000, + 0x38440000, + 0x38442000, + 0x38444000, + 0x38446000, + 0x38448000, + 0x3844a000, + 0x3844c000, + 0x3844e000, + 0x38450000, + 0x38452000, + 0x38454000, + 0x38456000, + 0x38458000, + 0x3845a000, + 0x3845c000, + 0x3845e000, + 0x38460000, + 0x38462000, + 0x38464000, + 0x38466000, + 0x38468000, + 0x3846a000, + 0x3846c000, + 0x3846e000, + 0x38470000, + 0x38472000, + 0x38474000, + 0x38476000, + 0x38478000, + 0x3847a000, + 0x3847c000, + 0x3847e000, + 0x38480000, + 0x38482000, + 0x38484000, + 0x38486000, + 0x38488000, + 0x3848a000, + 0x3848c000, + 0x3848e000, + 0x38490000, + 0x38492000, + 0x38494000, + 0x38496000, + 0x38498000, + 0x3849a000, + 0x3849c000, + 0x3849e000, + 0x384a0000, + 0x384a2000, + 0x384a4000, + 0x384a6000, + 0x384a8000, + 0x384aa000, + 0x384ac000, + 0x384ae000, + 0x384b0000, + 0x384b2000, + 0x384b4000, + 0x384b6000, + 0x384b8000, + 0x384ba000, + 0x384bc000, + 0x384be000, + 0x384c0000, + 0x384c2000, + 0x384c4000, + 0x384c6000, + 0x384c8000, + 0x384ca000, + 0x384cc000, + 0x384ce000, + 0x384d0000, + 0x384d2000, + 0x384d4000, + 0x384d6000, + 0x384d8000, + 0x384da000, + 0x384dc000, + 0x384de000, + 0x384e0000, + 0x384e2000, + 0x384e4000, + 0x384e6000, + 0x384e8000, + 0x384ea000, + 0x384ec000, + 0x384ee000, + 0x384f0000, + 0x384f2000, + 0x384f4000, + 0x384f6000, + 0x384f8000, + 0x384fa000, + 0x384fc000, + 0x384fe000, + 0x38500000, + 0x38502000, + 0x38504000, + 0x38506000, + 0x38508000, + 0x3850a000, + 0x3850c000, + 0x3850e000, + 0x38510000, + 0x38512000, + 0x38514000, + 0x38516000, + 0x38518000, + 0x3851a000, + 0x3851c000, + 0x3851e000, + 0x38520000, + 0x38522000, + 0x38524000, + 0x38526000, + 0x38528000, + 0x3852a000, + 0x3852c000, + 0x3852e000, + 0x38530000, + 0x38532000, + 0x38534000, + 0x38536000, + 0x38538000, + 0x3853a000, + 0x3853c000, + 0x3853e000, + 0x38540000, + 0x38542000, + 0x38544000, + 0x38546000, + 0x38548000, + 0x3854a000, + 0x3854c000, + 0x3854e000, + 0x38550000, + 0x38552000, + 0x38554000, + 0x38556000, + 0x38558000, + 0x3855a000, + 0x3855c000, + 0x3855e000, + 0x38560000, + 0x38562000, + 0x38564000, + 0x38566000, + 0x38568000, + 0x3856a000, + 0x3856c000, + 0x3856e000, + 0x38570000, + 0x38572000, + 0x38574000, + 0x38576000, + 0x38578000, + 0x3857a000, + 0x3857c000, + 0x3857e000, + 0x38580000, + 0x38582000, + 0x38584000, + 0x38586000, + 0x38588000, + 0x3858a000, + 0x3858c000, + 0x3858e000, + 0x38590000, + 0x38592000, + 0x38594000, + 0x38596000, + 0x38598000, + 0x3859a000, + 0x3859c000, + 0x3859e000, + 0x385a0000, + 0x385a2000, + 0x385a4000, + 0x385a6000, + 0x385a8000, + 0x385aa000, + 0x385ac000, + 0x385ae000, + 0x385b0000, + 0x385b2000, + 0x385b4000, + 0x385b6000, + 0x385b8000, + 0x385ba000, + 0x385bc000, + 0x385be000, + 0x385c0000, + 0x385c2000, + 0x385c4000, + 0x385c6000, + 0x385c8000, + 0x385ca000, + 0x385cc000, + 0x385ce000, + 0x385d0000, + 0x385d2000, + 0x385d4000, + 0x385d6000, + 0x385d8000, + 0x385da000, + 0x385dc000, + 0x385de000, + 0x385e0000, + 0x385e2000, + 0x385e4000, + 0x385e6000, + 0x385e8000, + 0x385ea000, + 0x385ec000, + 0x385ee000, + 0x385f0000, + 0x385f2000, + 0x385f4000, + 0x385f6000, + 0x385f8000, + 0x385fa000, + 0x385fc000, + 0x385fe000, + 0x38600000, + 0x38602000, + 0x38604000, + 0x38606000, + 0x38608000, + 0x3860a000, + 0x3860c000, + 0x3860e000, + 0x38610000, + 0x38612000, + 0x38614000, + 0x38616000, + 0x38618000, + 0x3861a000, + 0x3861c000, + 0x3861e000, + 0x38620000, + 0x38622000, + 0x38624000, + 0x38626000, + 0x38628000, + 0x3862a000, + 0x3862c000, + 0x3862e000, + 0x38630000, + 0x38632000, + 0x38634000, + 0x38636000, + 0x38638000, + 0x3863a000, + 0x3863c000, + 0x3863e000, + 0x38640000, + 0x38642000, + 0x38644000, + 0x38646000, + 0x38648000, + 0x3864a000, + 0x3864c000, + 0x3864e000, + 0x38650000, + 0x38652000, + 0x38654000, + 0x38656000, + 0x38658000, + 0x3865a000, + 0x3865c000, + 0x3865e000, + 0x38660000, + 0x38662000, + 0x38664000, + 0x38666000, + 0x38668000, + 0x3866a000, + 0x3866c000, + 0x3866e000, + 0x38670000, + 0x38672000, + 0x38674000, + 0x38676000, + 0x38678000, + 0x3867a000, + 0x3867c000, + 0x3867e000, + 0x38680000, + 0x38682000, + 0x38684000, + 0x38686000, + 0x38688000, + 0x3868a000, + 0x3868c000, + 0x3868e000, + 0x38690000, + 0x38692000, + 0x38694000, + 0x38696000, + 0x38698000, + 0x3869a000, + 0x3869c000, + 0x3869e000, + 0x386a0000, + 0x386a2000, + 0x386a4000, + 0x386a6000, + 0x386a8000, + 0x386aa000, + 0x386ac000, + 0x386ae000, + 0x386b0000, + 0x386b2000, + 0x386b4000, + 0x386b6000, + 0x386b8000, + 0x386ba000, + 0x386bc000, + 0x386be000, + 0x386c0000, + 0x386c2000, + 0x386c4000, + 0x386c6000, + 0x386c8000, + 0x386ca000, + 0x386cc000, + 0x386ce000, + 0x386d0000, + 0x386d2000, + 0x386d4000, + 0x386d6000, + 0x386d8000, + 0x386da000, + 0x386dc000, + 0x386de000, + 0x386e0000, + 0x386e2000, + 0x386e4000, + 0x386e6000, + 0x386e8000, + 0x386ea000, + 0x386ec000, + 0x386ee000, + 0x386f0000, + 0x386f2000, + 0x386f4000, + 0x386f6000, + 0x386f8000, + 0x386fa000, + 0x386fc000, + 0x386fe000, + 0x38700000, + 0x38702000, + 0x38704000, + 0x38706000, + 0x38708000, + 0x3870a000, + 0x3870c000, + 0x3870e000, + 0x38710000, + 0x38712000, + 0x38714000, + 0x38716000, + 0x38718000, + 0x3871a000, + 0x3871c000, + 0x3871e000, + 0x38720000, + 0x38722000, + 0x38724000, + 0x38726000, + 0x38728000, + 0x3872a000, + 0x3872c000, + 0x3872e000, + 0x38730000, + 0x38732000, + 0x38734000, + 0x38736000, + 0x38738000, + 0x3873a000, + 0x3873c000, + 0x3873e000, + 0x38740000, + 0x38742000, + 0x38744000, + 0x38746000, + 0x38748000, + 0x3874a000, + 0x3874c000, + 0x3874e000, + 0x38750000, + 0x38752000, + 0x38754000, + 0x38756000, + 0x38758000, + 0x3875a000, + 0x3875c000, + 0x3875e000, + 0x38760000, + 0x38762000, + 0x38764000, + 0x38766000, + 0x38768000, + 0x3876a000, + 0x3876c000, + 0x3876e000, + 0x38770000, + 0x38772000, + 0x38774000, + 0x38776000, + 0x38778000, + 0x3877a000, + 0x3877c000, + 0x3877e000, + 0x38780000, + 0x38782000, + 0x38784000, + 0x38786000, + 0x38788000, + 0x3878a000, + 0x3878c000, + 0x3878e000, + 0x38790000, + 0x38792000, + 0x38794000, + 0x38796000, + 0x38798000, + 0x3879a000, + 0x3879c000, + 0x3879e000, + 0x387a0000, + 0x387a2000, + 0x387a4000, + 0x387a6000, + 0x387a8000, + 0x387aa000, + 0x387ac000, + 0x387ae000, + 0x387b0000, + 0x387b2000, + 0x387b4000, + 0x387b6000, + 0x387b8000, + 0x387ba000, + 0x387bc000, + 0x387be000, + 0x387c0000, + 0x387c2000, + 0x387c4000, + 0x387c6000, + 0x387c8000, + 0x387ca000, + 0x387cc000, + 0x387ce000, + 0x387d0000, + 0x387d2000, + 0x387d4000, + 0x387d6000, + 0x387d8000, + 0x387da000, + 0x387dc000, + 0x387de000, + 0x387e0000, + 0x387e2000, + 0x387e4000, + 0x387e6000, + 0x387e8000, + 0x387ea000, + 0x387ec000, + 0x387ee000, + 0x387f0000, + 0x387f2000, + 0x387f4000, + 0x387f6000, + 0x387f8000, + 0x387fa000, + 0x387fc000, + 0x387fe000, +}; + +const static unsigned g_exponent[64] = { + 0x00000000, + 0x00800000, + 0x01000000, + 0x01800000, + 0x02000000, + 0x02800000, + 0x03000000, + 0x03800000, + 0x04000000, + 0x04800000, + 0x05000000, + 0x05800000, + 0x06000000, + 0x06800000, + 0x07000000, + 0x07800000, + 0x08000000, + 0x08800000, + 0x09000000, + 0x09800000, + 0x0a000000, + 0x0a800000, + 0x0b000000, + 0x0b800000, + 0x0c000000, + 0x0c800000, + 0x0d000000, + 0x0d800000, + 0x0e000000, + 0x0e800000, + 0x0f000000, + 0x47800000, + 0x80000000, + 0x80800000, + 0x81000000, + 0x81800000, + 0x82000000, + 0x82800000, + 0x83000000, + 0x83800000, + 0x84000000, + 0x84800000, + 0x85000000, + 0x85800000, + 0x86000000, + 0x86800000, + 0x87000000, + 0x87800000, + 0x88000000, + 0x88800000, + 0x89000000, + 0x89800000, + 0x8a000000, + 0x8a800000, + 0x8b000000, + 0x8b800000, + 0x8c000000, + 0x8c800000, + 0x8d000000, + 0x8d800000, + 0x8e000000, + 0x8e800000, + 0x8f000000, + 0xc7800000, +}; + +const static unsigned g_offset[64] = { + 0x00000000, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000000, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, +}; + +float float16ToFloat32(unsigned short h) +{ + unsigned i32 = g_mantissa[g_offset[h >> 10] + (h & 0x3ff)] + g_exponent[h >> 10]; + return bitCast(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 + +#include #include +namespace angle +{ +const uintptr_t DirtyPointer = std::numeric_limits::max(); +} + size_t FormatStringIntoVector(const char *fmt, va_list vararg, std::vector& 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 @@ -72,9 +71,9 @@ void SafeDelete(T*& resource) template 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(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(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(std::max(red_c, green_c), blue_c); const float exp_p = std::max(-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(floor((max_c / (pow(2.0f, exp_p - g_sharedexp_bias - g_sharedexp_mantissabits))) + 0.5f)); + const int exp_s = static_cast((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(floor((red_c / (pow(2.0f, exp_s - g_sharedexp_bias - g_sharedexp_mantissabits))) + 0.5f)); + output.G = static_cast(floor((green_c / (pow(2.0f, exp_s - g_sharedexp_bias - g_sharedexp_mantissabits))) + 0.5f)); + output.B = static_cast(floor((blue_c / (pow(2.0f, exp_s - g_sharedexp_bias - g_sharedexp_mantissabits))) + 0.5f)); output.E = exp_s; - return *reinterpret_cast(&output); + return bitCast(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 #include +#include #include +#include #include namespace gl @@ -67,14 +69,29 @@ inline int clampToInt(unsigned int x) template 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(static_cast(std::numeric_limits::min())) == std::numeric_limits::min()); - ASSERT(static_cast(static_cast(std::numeric_limits::max())) == std::numeric_limits::max()); - - SrcT lo = static_cast(std::numeric_limits::min()); - SrcT hi = static_cast(std::numeric_limits::max()); - return static_cast(value > lo ? (value > hi ? hi : value) : lo); + static const DestT destLo = std::numeric_limits::min(); + static const DestT destHi = std::numeric_limits::max(); + static const SrcT srcLo = static_cast(destLo); + static const SrcT srcHi = static_cast(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(value); + } } template @@ -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(fp32); unsigned int sign = (fp32i & 0x80000000) >> 16; unsigned int abs = fp32i & 0x7FFFFFFF; if(abs > 0x47FFEFFF) // Infinity { - return sign | 0x7FFF; + return static_cast(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(sign | (abs + 0x00000FFF + ((abs >> 13) & 1)) >> 13); } else { - return sign | (abs + 0xC8000000 + 0x00000FFF + ((abs >> 13) & 1)) >> 13; + return static_cast(sign | (abs + 0xC8000000 + 0x00000FFF + ((abs >> 13) & 1)) >> 13); } } @@ -426,14 +439,14 @@ inline float normalizedToFloat(T input) template inline T floatToNormalized(float input) { - return std::numeric_limits::max() * input + 0.5f; + return static_cast(std::numeric_limits::max() * input + 0.5f); } template 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(((1 << outputBitCount) - 1) * input + 0.5f); } template @@ -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(a) + static_cast(b)) / 2ll; + return static_cast(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(a)) + float11ToFloat32(static_cast(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(a)) + float10ToFloat32(static_cast(b))) * 0.5f); } -namespace rx -{ - -// Represents intervals of the type [a, b) template 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 RangeI; typedef Range 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(roundf(clamp(f1, -1.0f, 1.0f) * 32767.0f)); + int16_t mostSignificantBits = static_cast(roundf(clamp(f2, -1.0f, 1.0f) * 32767.0f)); + return static_cast(mostSignificantBits) << 16 | + (static_cast(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(u & 0xFFFF); + int16_t mostSignificantBits = static_cast(u >> 16); + *f1 = clamp(static_cast(leastSignificantBits) / 32767.0f, -1.0f, 1.0f); + *f2 = clamp(static_cast(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(roundf(clamp(f1, 0.0f, 1.0f) * 65535.0f)); + uint16_t mostSignificantBits = static_cast(roundf(clamp(f2, 0.0f, 1.0f) * 65535.0f)); + return static_cast(mostSignificantBits) << 16 | static_cast(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(u & 0xFFFF); + uint16_t mostSignificantBits = static_cast(u >> 16); + *f1 = static_cast(leastSignificantBits) / 65535.0f; + *f2 = static_cast(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(float32ToFloat16(f1)); + uint16_t mostSignificantBits = static_cast(float32ToFloat16(f2)); + return static_cast(mostSignificantBits) << 16 | static_cast(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(u & 0xFFFF); + uint16_t mostSignificantBits = static_cast(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(f) & 0x7f800000u) == 0x7f800000u) && (bitCast(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(f) & 0x7f800000u) == 0x7f800000u) && !(bitCast(f) & 0x7fffffu); +} + +} + +namespace rx +{ + template 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 + +#include "common/debug.h" + +namespace angle +{ + +template +class Matrix +{ + public: + Matrix(const std::vector &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 &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 operator*(const Matrix &m) + { + ASSERT(columns() == m.rows()); + + unsigned int resultRows = rows(); + unsigned int resultCols = m.columns(); + Matrix result(std::vector(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 elements() const { return mElements; } + + Matrix compMult(const Matrix &mat1) const + { + Matrix result(std::vector(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 outerProduct(const Matrix &mat1) const + { + unsigned int cols = mat1.columns(); + Matrix result(std::vector(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 transpose() const + { + Matrix result(std::vector(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(minorMatrices[0], 3).determinant() - + at(0, 1) * Matrix(minorMatrices[1], 3).determinant() + + at(0, 2) * Matrix(minorMatrices[2], 3).determinant() - + at(0, 3) * Matrix(minorMatrices[3], 3).determinant(); + } + + default: + UNREACHABLE(); + break; + } + + return T(); + } + + Matrix inverse() const + { + ASSERT(rows() == columns()); + + Matrix cof(std::vector(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 adjugateMatrix(cof.transpose()); + T det = determinant(); + Matrix result(std::vector(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 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 -# if !defined(ANGLE_TRANSLATOR_IMPLEMENTATION) # include -# endif # endif # if defined(ANGLE_ENABLE_D3D11) @@ -72,9 +70,7 @@ # include # include # endif -# if !defined(ANGLE_TRANSLATOR_IMPLEMENTATION) # include -# 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 +#include + +namespace angle +{ + +const char kWhitespaceASCII[] = " \f\n\r\t\v"; + +std::vector SplitString(const std::string &input, + const std::string &delimiters, + WhitespaceHandling whitespace, + SplitResult resultType) +{ + std::vector 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 *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(inFile.tellg())); + inFile.seekg(0, std::ios::beg); + + stringOut->assign(std::istreambuf_iterator(inFile), std::istreambuf_iterator()); + 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 +#include + +namespace angle +{ + +extern const char kWhitespaceASCII[]; + +enum WhitespaceHandling +{ + KEEP_WHITESPACE, + TRIM_WHITESPACE, +}; + +enum SplitResult +{ + SPLIT_WANT_ALL, + SPLIT_WANT_NONEMPTY, +}; + +std::vector SplitString(const std::string &input, + const std::string &delimiters, + WhitespaceHandling whitespace, + SplitResult resultType); + +void SplitStringAlongWhitespace(const std::string &input, + std::vector *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 #endif +namespace +{ + +template +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(minIndex), static_cast(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(index); } +IndexRange ComputeIndexRange(GLenum indexType, + const GLvoid *indices, + size_t count, + bool primitiveRestartEnabled) +{ + switch (indexType) + { + case GL_UNSIGNED_BYTE: + return ComputeTypedIndexRange(static_cast(indices), count, + primitiveRestartEnabled, + GetPrimitiveRestartIndex(indexType)); + case GL_UNSIGNED_SHORT: + return ComputeTypedIndexRange(static_cast(indices), count, + primitiveRestartEnabled, + GetPrimitiveRestartIndex(indexType)); + case GL_UNSIGNED_INT: + return ComputeTypedIndexRange(static_cast(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(FirstCubeMapTextureTarget); +} + +EGLenum LayerIndexToCubeMapTextureTarget(size_t index) +{ + ASSERT(index <= (LastCubeMapTextureTarget - FirstCubeMapTextureTarget)); + return FirstCubeMapTextureTarget + static_cast(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(reinterpret_cast(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 +#include + #include "angle_gl.h" #include #include +#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 outT iround(GLfloat value) { return static_cast(value > 0.0f ? floor(value + 0.5f) : ceil(value - 0.5f)); } template outT uiround(GLfloat value) { return static_cast(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 #include #include #include @@ -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(¯oExpander, 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(¯oExpander, 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 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 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(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(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(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(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(val); type = TOK_CONST_INT; break; } + case pp::Token::IDENTIFIER: + *lvalp = static_cast(-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 + #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 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 ¯o, std::vector *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 ¯o, assert(macro.type == Macro::kTypeFunc); std::vector 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 ¯o, repl.setAtStartOfLine(identifier.atStartOfLine()); repl.setHasLeadingSpace(identifier.hasLeadingSpace()); } - repl.location = identifier.location; + repl.location = replacementLocation; } return true; } bool MacroExpander::collectMacroArgs(const Macro ¯o, const Token &identifier, - std::vector *args) + std::vector *args, + SourceLocation *closingParenthesisLocation) { Token token; getToken(&token); @@ -271,6 +320,7 @@ bool MacroExpander::collectMacroArgs(const Macro ¯o, 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 ¯o, { 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 MacroArg; bool collectMacroArgs(const Macro ¯o, const Token &identifier, - std::vector *args); + std::vector *args, + SourceLocation *closingParenthesisLocation); void replaceMacroParams(const Macro ¯o, const std::vector &args, std::vector *replacements); @@ -79,6 +81,7 @@ class MacroExpander : public Lexer Lexer *mLexer; MacroSet *mMacroSet; Diagnostics *mDiagnostics; + bool mParseDefined; std::auto_ptr mReserveToken; std::vector 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 -#include #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, ¯oSet, diag, directiveHandler), - macroExpander(&directiveParser, ¯oSet, diag) + macroExpander(&directiveParser, ¯oSet, 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); } [^*\r\n]+ "*" 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 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 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 mLoopsAndSwitches; + std::vector 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 +#include + +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 mControlFlowsContainingGradient; + + // Remember information about the discontinuous loops and which functions + // are called in such loops. + bool mCalledInDiscontinuousLoop; + bool mHasGradientLoopInCallGraph; + std::set mDiscontinuousLoops; + std::set mIfsContainingGradientLoop; + + // Will we need to generate a Lod0 version of the function. + bool mNeedsLod0; +}; + +typedef std::vector 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 ¶m : *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 ¶m) { - return SetFunctionCalled(FunctionId(op, param)); + return SetFunctionCalled(FunctionId(op, ¶m)); } -bool BuiltInFunctionEmulator::SetFunctionCalled( - TOperator op, const TType& param1, const TType& param2) +bool BuiltInFunctionEmulator::SetFunctionCalled(TOperator op, const TType ¶m1, const TType ¶m2) { - return SetFunctionCalled(FunctionId(op, param1, param2)); + return SetFunctionCalled(FunctionId(op, ¶m1, ¶m2)); } -bool BuiltInFunctionEmulator::SetFunctionCalled( - TOperator op, const TType& param1, const TType& param2, const TType& param3) +bool BuiltInFunctionEmulator::SetFunctionCalled(TOperator op, + const TType ¶m1, const TType ¶m2, const TType ¶m3) { - return SetFunctionCalled(FunctionId(op, param1, param2, param3)); + return SetFunctionCalled(FunctionId(op, ¶m1, ¶m2, ¶m3)); } -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 ¶m); + bool SetFunctionCalled(TOperator op, const TType ¶m1, const TType ¶m2); + bool SetFunctionCalled(TOperator op, const TType ¶m1, const TType ¶m2, const TType ¶m3); 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 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 + +#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::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(basicType); + components.precision = static_cast(precision); + components.qualifier = static_cast(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 +#include +#include + +#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 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 *records, std::map *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(callee->index)); + } + + (*idToIndex)[data.node->getFunctionId()] = static_cast(data.index); + } + } + + private: + + struct CreatorFunctionData + { + CreatorFunctionData() + : node(nullptr), + index(0), + indexAssigned(false), + visiting(false) + { + } + + std::set 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 mFunctions; + CreatorFunctionData *mCurrentFunction; + size_t mCurrentIndex; +}; + +// CallDAG + +CallDAG::CallDAG() +{ +} + +CallDAG::~CallDAG() +{ +} + +const size_t CallDAG::InvalidIndex = std::numeric_limits::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 + +#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 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 mRecords; + std::map 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 #include -#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 TVector : public std::vector > { -public: - typedef typename std::vector >::size_type size_type; - TVector() : std::vector >() {} - TVector(const pool_allocator& a) : std::vector >(a) {} - TVector(size_type i): std::vector >(i) {} +template +class TVector : public std::vector> +{ + public: + typedef typename std::vector>::size_type size_type; + TVector() : std::vector>() {} + TVector(const pool_allocator &a) : std::vector>(a) {} + TVector(size_type i) : std::vector>(i) {} }; -template > -class TMap : public std::map > > { -public: - typedef pool_allocator > tAllocator; +template > +class TMap : public std::map>> +{ + public: + typedef pool_allocator> tAllocator; TMap() : std::map() {} // 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(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 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(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 *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 *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" @@ -35,6 +36,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. // @@ -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 &getAttributes() const { return attributes; } - const std::vector &getOutputVariables() const { return outputVariables; } + const std::vector &getOutputVariables() const { return outputVariables; } const std::vector &getUniforms() const { return uniforms; } const std::vector &getVaryings() const { return varyings; } const std::vector &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 attributes; - std::vector outputVariables; + std::vector outputVariables; std::vector uniforms; std::vector expandedUniforms; std::vector varyings; std::vector 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; + 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 -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 -#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 mSeqIterStack; - bool mDeclaringVariables; - bool mInLValue; - bool mInFunctionCallOutParameter; - - struct TStringComparator - { - bool operator() (const TString& a, const TString& b) const { return a.compare(b) < 0; } - }; - - // Map from function names to their parameter sequences - std::map mFunctionMap; }; #endif // COMPILER_TRANSLATOR_EMULATE_PRECISION_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/ExtensionBehavior.h b/src/3rdparty/angle/src/compiler/translator/ExtensionBehavior.h index 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 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 &TExtensionGLSL::getEnabledExtensions() const +{ + return mEnabledExtensions; +} + +const std::set &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 +#include + +#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 &getEnabledExtensions() const; + const std::set &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 mEnabledExtensions; + std::set 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 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(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 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 #include +#include +#include #include +#include +#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 GetMatrix(const TConstantUnion *paramArray, + const unsigned int &rows, + const unsigned int &cols) +{ + std::vector 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(elements, rows, cols).transpose(); +} + +angle::Matrix GetMatrix(const TConstantUnion *paramArray, const unsigned int &size) +{ + std::vector 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(elements, size).transpose(); +} + +void SetUnionArrayFromMatrix(const angle::Matrix &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 result = m.transpose(); + std::vector 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(mRight->getCols()), 1)); } else { mOp = EOpMatrixTimesScalar; - setType(TType(basicType, higherPrecision, EvqTemporary, - mRight->getCols(), mRight->getRows())); + setType(TType(basicType, higherPrecision, resultQualifier, + static_cast(mRight->getCols()), + static_cast(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(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(mRight->getCols()), + static_cast(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(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(mRight->getCols()), + static_cast(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(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(nominalSize), + static_cast(secondarySize))); if (mLeft->isArray()) { ASSERT(mLeft->getArraySize() == mRight->getArraySize()); @@ -639,308 +818,1332 @@ 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: + case EOpMatrixTimesVector: + { + if (rightNode->getBasicType() != EbtFloat) { - if (node->getBasicType() != EbtFloat) - { - infoSink.info.message( - EPrefixInternalError, getLine(), - "Constant Folding cannot be done for matrix times vector"); - return NULL; - } + infoSink.info.message(EPrefixInternalError, getLine(), + "Constant Folding cannot be done for matrix times vector"); + return nullptr; + } - const int matrixCols = getCols(); - const int matrixRows = getRows(); + const int matrixCols = getCols(); + const int matrixRows = getRows(); - tempConstArray = new ConstantUnion[matrixRows]; + resultArray = new TConstantUnion[matrixRows]; - for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++) + for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++) + { + resultArray[matrixRow].setFConst(0.0f); + for (int col = 0; col < matrixCols; col++) { - 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[matrixRow].setFConst(resultArray[matrixRow].getFConst() + + leftArray[col * matrixRows + matrixRow].getFConst() * + rightArray[col].getFConst()); } - - returnType = node->getType(); - returnType.setPrimarySize(matrixRows); - - tempNode = new TIntermConstantUnion(tempConstArray, returnType); - tempNode->setLine(getLine()); - - return tempNode; } + } + break; - case EOpVectorTimesMatrix: + case EOpVectorTimesMatrix: + { + if (getType().getBasicType() != EbtFloat) { - if (getType().getBasicType() != EbtFloat) - { - infoSink.info.message( - EPrefixInternalError, getLine(), - "Constant Folding cannot be done for vector times matrix"); - return NULL; - } + infoSink.info.message(EPrefixInternalError, getLine(), + "Constant Folding cannot be done for vector times matrix"); + return nullptr; + } - const int matrixCols = constantNode->getType().getCols(); - const int matrixRows = constantNode->getType().getRows(); + const int matrixCols = rightNode->getType().getCols(); + const int matrixRows = rightNode->getType().getRows(); - tempConstArray = new ConstantUnion[matrixCols]; + resultArray = new TConstantUnion[matrixCols]; - for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++) + for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++) + { + resultArray[matrixCol].setFConst(0.0f); + for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++) { - 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()); - } + resultArray[matrixCol].setFConst(resultArray[matrixCol].getFConst() + + leftArray[matrixRow].getFConst() * + rightArray[matrixCol * matrixRows + matrixRow].getFConst()); } - - returnType.setPrimarySize(matrixCols); } - break; + } + break; - case EOpLogicalAnd: - // this code is written for possible future use, + case EOpLogicalAnd: + { + resultArray = new TConstantUnion[objectSize]; + for (size_t i = 0; i < objectSize; i++) + { + resultArray[i] = leftArray[i] && rightArray[i]; + } + } + break; + + case EOpLogicalOr: + { + resultArray = new TConstantUnion[objectSize]; + for (size_t i = 0; i < objectSize; i++) + { + resultArray[i] = leftArray[i] || rightArray[i]; + } + } + break; + + case EOpLogicalXor: + { + resultArray = new TConstantUnion[objectSize]; + for (size_t i = 0; i < objectSize; i++) + { + switch (getType().getBasicType()) + { + case EbtBool: + resultArray[i].setBConst(leftArray[i] != rightArray[i]); + break; + default: + UNREACHABLE(); + break; + } + } + } + break; + + 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; + + case EOpGreaterThan: + ASSERT(objectSize == 1); + resultArray = new TConstantUnion[1]; + resultArray->setBConst(*leftArray > *rightArray); + break; + + 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]) + { + 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; + + 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 EOpAll: + if (getType().getBasicType() == EbtBool) + { + resultArray = new TConstantUnion(); + resultArray->setBConst(true); + for (size_t i = 0; i < objectSize; i++) + { + if (!operandArray[i].getBConst()) + { + resultArray->setBConst(false); + break; + } + } + break; + } + else + { + infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant"); + return nullptr; + } + + 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 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 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( + -static_cast(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( + static_cast(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()) + { + 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 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) + { + 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: + { + 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 EOpFloor: + if (!foldFloatTypeUnary(operandArray[i], &floorf, infoSink, &resultArray[i])) + return nullptr; + break; + + case EOpTrunc: + if (!foldFloatTypeUnary(operandArray[i], &truncf, infoSink, &resultArray[i])) + return nullptr; + break; + + case EOpRound: + if (!foldFloatTypeUnary(operandArray[i], &roundf, infoSink, &resultArray[i])) + return nullptr; + break; + + 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 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(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(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(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(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 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 EOpExp2: + if (!foldFloatTypeUnary(operandArray[i], &exp2f, infoSink, &resultArray[i])) + return nullptr; + break; + + 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) + { + resultArray[i].setBConst(!operandArray[i].getBConst()); + break; + } + infoSink.info.message( + EPrefixInternalError, getLine(), + "Unary operation not folded into constant"); + return nullptr; + + case EOpNormalize: + if (getType().getBasicType() == EbtFloat) + { + 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 EOpDFdx: + case EOpDFdy: + case EOpFwidth: + if (getType().getBasicType() == EbtFloat) + { + // 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 ¶meter, 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) + { + for (int row = 0; row < resultRows; ++row) + { + if (col == row) + { + resultArray[resultIndex].cast(basicType, argumentUnionArray[0]); + } + else + { + resultArray[resultIndex].setFConst(0.0f); + } + ++resultIndex; + } + } + } + else + { + while (resultIndex < resultSize) + { + 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) + { + resultArray[resultIndex].setFConst(1.0f); + } + else + { + resultArray[resultIndex].setFConst(0.0f); + } + ++resultIndex; + } + } + ASSERT(resultIndex == resultSize); + return resultArray; + } + } + + 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(sequence->size()); + std::vector unionArrays(paramsCount); + std::vector 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: + { + 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(); + } + break; + + case EOpPow: + { + 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; + + case EOpMod: { - tempConstArray = new ConstantUnion[objectSize]; - for (size_t i = 0; i < objectSize; i++) + if (basicType == EbtFloat) { - tempConstArray[i] = unionArray[i] && rightUnionArray[i]; + 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; - case EOpLogicalOr: - // this code is written for possible future use, - // will not get executed currently + case EOpMin: { - tempConstArray = new ConstantUnion[objectSize]; - for (size_t i = 0; i < objectSize; i++) + resultArray = new TConstantUnion[maxObjectSize]; + for (size_t i = 0; i < maxObjectSize; i++) { - tempConstArray[i] = unionArray[i] || rightUnionArray[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 EOpLogicalXor: + case EOpMax: { - tempConstArray = new ConstantUnion[objectSize]; - for (size_t i = 0; i < objectSize; i++) + resultArray = new TConstantUnion[maxObjectSize]; + for (size_t i = 0; i < maxObjectSize; i++) { - switch (getType().getBasicType()) + switch (basicType) { - case EbtBool: - tempConstArray[i].setBConst( - unionArray[i] == rightUnionArray[i] ? false : true); + 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(); @@ -950,249 +2153,443 @@ TIntermTyped *TIntermConstantUnion::fold( } break; - case EOpBitwiseAnd: - tempConstArray = new ConstantUnion[objectSize]; - for (size_t i = 0; i < objectSize; i++) - tempConstArray[i] = unionArray[i] & rightUnionArray[i]; - break; - case EOpBitwiseXor: - tempConstArray = new ConstantUnion[objectSize]; - for (size_t i = 0; i < objectSize; i++) - tempConstArray[i] = unionArray[i] ^ rightUnionArray[i]; - break; - case EOpBitwiseOr: - tempConstArray = new ConstantUnion[objectSize]; - for (size_t i = 0; i < objectSize; i++) - tempConstArray[i] = unionArray[i] | rightUnionArray[i]; - break; - case EOpBitShiftLeft: - tempConstArray = new ConstantUnion[objectSize]; - for (size_t i = 0; i < objectSize; i++) - tempConstArray[i] = unionArray[i] << rightUnionArray[i]; - break; - case EOpBitShiftRight: - tempConstArray = new ConstantUnion[objectSize]; - for (size_t i = 0; i < objectSize; i++) - tempConstArray[i] = unionArray[i] >> rightUnionArray[i]; + case EOpStep: + { + if (basicType == EbtFloat) + { + 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: - ASSERT(objectSize == 1); - tempConstArray = new ConstantUnion[1]; - tempConstArray->setBConst(*unionArray < *rightUnionArray); - returnType = TType(EbtBool, EbpUndefined, EvqConst); + { + 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: - ASSERT(objectSize == 1); - tempConstArray = new ConstantUnion[1]; - tempConstArray->setBConst(*unionArray > *rightUnionArray); - returnType = TType(EbtBool, EbpUndefined, EvqConst); + 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 EOpLessThanEqual: + case EOpGreaterThan: { - ASSERT(objectSize == 1); - ConstantUnion constant; - constant.setBConst(*unionArray > *rightUnionArray); - tempConstArray = new ConstantUnion[1]; - tempConstArray->setBConst(!constant.getBConst()); - returnType = TType(EbtBool, EbpUndefined, EvqConst); - break; + 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: { - ASSERT(objectSize == 1); - ConstantUnion constant; - constant.setBConst(*unionArray < *rightUnionArray); - tempConstArray = new ConstantUnion[1]; - tempConstArray->setBConst(!constant.getBConst()); - returnType = TType(EbtBool, EbpUndefined, EvqConst); - break; + 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 EOpEqual: - if (getType().getBasicType() == EbtStruct) + case EOpVectorEqual: { - 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].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; + } } } - else + break; + + case EOpVectorNotEqual: { - for (size_t i = 0; i < objectSize; i++) + resultArray = new TConstantUnion[maxObjectSize]; + for (size_t i = 0; i < maxObjectSize; i++) { - if (unionArray[i] != rightUnionArray[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; + case EbtBool: + resultArray[i].setBConst(unionArrays[0][i].getBConst() != unionArrays[1][i].getBConst()); + break; + default: + UNREACHABLE(); + break; } } } + break; - tempConstArray = new ConstantUnion[1]; - if (!boolNodeFlag) + case EOpDistance: + if (basicType == EbtFloat) { - tempConstArray->setBConst(true); + 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 - { - tempConstArray->setBConst(false); - } + UNREACHABLE(); + break; - tempNode = new TIntermConstantUnion( - tempConstArray, TType(EbtBool, EbpUndefined, EvqConst)); - tempNode->setLine(getLine()); + case EOpDot: - return tempNode; + if (basicType == EbtFloat) + { + resultArray = new TConstantUnion(); + resultArray->setFConst(VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize)); + } + else + UNREACHABLE(); + break; - case EOpNotEqual: - if (getType().getBasicType() == EbtStruct) + case EOpCross: + if (basicType == EbtFloat && maxObjectSize == 3) { - if (CompareStructure(node->getType(), - node->getUnionArrayPointer(), - unionArray)) - { - boolNodeFlag = 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) { - for (size_t i = 0; i < objectSize; i++) + // 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++) { - if (unionArray[i] == rightUnionArray[i]) - { - boolNodeFlag = true; - break; // break out of for loop - } + float result = unionArrays[0][i].getFConst() - + 2.0f * dotProduct * unionArrays[1][i].getFConst(); + resultArray[i].setFConst(result); } } + else + UNREACHABLE(); + break; - tempConstArray = new ConstantUnion[1]; - if (!boolNodeFlag) + case EOpMul: + if (basicType == EbtFloat && (*sequence)[0]->getAsTyped()->isMatrix() && + (*sequence)[1]->getAsTyped()->isMatrix()) { - tempConstArray->setBConst(true); + // Perform component-wise matrix multiplication. + resultArray = new TConstantUnion[maxObjectSize]; + int size = (*sequence)[0]->getAsTyped()->getNominalSize(); + angle::Matrix result = + GetMatrix(unionArrays[0], size).compMult(GetMatrix(unionArrays[1], size)); + SetUnionArrayFromMatrix(result, resultArray); } else + UNREACHABLE(); + break; + + case EOpOuterProduct: + if (basicType == EbtFloat) { - tempConstArray->setBConst(false); + size_t numRows = (*sequence)[0]->getAsTyped()->getType().getObjectSize(); + size_t numCols = (*sequence)[1]->getAsTyped()->getType().getObjectSize(); + resultArray = new TConstantUnion[numRows * numCols]; + angle::Matrix result = + GetMatrix(unionArrays[0], 1, static_cast(numCols)) + .outerProduct(GetMatrix(unionArrays[1], static_cast(numRows), 1)); + SetUnionArrayFromMatrix(result, resultArray); } - - tempNode = new TIntermConstantUnion( - tempConstArray, TType(EbtBool, EbpUndefined, EvqConst)); - tempNode->setLine(getLine()); - - return tempNode; + 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( - -static_cast(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( - static_cast(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 ¶meter, 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 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 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 mReplacements; + std::vector mMultiReplacements; + std::vector 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 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 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(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 } }; -class FindSideEffectRewriting : public NodeSearchTraverser -{ - 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 @@ -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 #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 &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 x, SamplerState s"; hlslCoords = 2; break; - case EbtISampler3D: out << "Texture3D x, SamplerState s"; hlslCoords = 3; break; - case EbtISamplerCube: out << "Texture2DArray x, SamplerState s"; hlslCoords = 3; break; - case EbtISampler2DArray: out << "Texture2DArray x, SamplerState s"; hlslCoords = 3; break; - case EbtUSampler2D: out << "Texture2D x, SamplerState s"; hlslCoords = 2; break; - case EbtUSampler3D: out << "Texture3D x, SamplerState s"; hlslCoords = 3; break; - case EbtUSamplerCube: out << "Texture2DArray x, SamplerState s"; hlslCoords = 3; break; - case EbtUSampler2DArray: out << "Texture2DArray x, SamplerState s"; hlslCoords = 3; break; - case EbtSampler2DShadow: out << "Texture2D x, SamplerComparisonState s"; hlslCoords = 2; break; - case EbtSamplerCubeShadow: out << "TextureCube x, SamplerComparisonState s"; hlslCoords = 3; break; - case EbtSampler2DArrayShadow: out << "Texture2DArray x, SamplerComparisonState s"; hlslCoords = 3; break; - default: UNREACHABLE(); + 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 #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 &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 mFlaggedStructMappedNames; std::map 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> 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 mArrayEqualityFunctions; std::vector 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 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 #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 ¶m = 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(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(function.getParamCount())); + } + else if (static_cast(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(unsignedSize); + size = static_cast(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(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(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( + 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)) - return true; - - // check for layout qualifier issues - const TLayoutQualifier layoutQualifier = publicType.layoutQualifier; - - if (layoutQualifier.matrixPacking != EmpUnspecified) + switch (publicType.qualifier) { - error(identifierLocation, "layout qualifier", getMatrixPackingString(layoutQualifier.matrixPacking), "only valid for interface blocks"); - return true; + 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"); + 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(symbol); + variable = static_cast(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(symbol); + return static_cast(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(symbol); + *intermNode = nullptr; + return false; + } + else if (initializer->getAsSymbolNode()) + { + const TSymbol *symbol = + symbolTable.find(initializer->getAsSymbolNode()->getSymbol(), 0); + const TVariable *tVar = static_cast(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); - if (identifier != "") + bool emptyDeclaration = (identifier == ""); + + mDeferredSingleDeclarationErrorCheck = emptyDeclaration; + + if (emptyDeclaration) + { + 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, identifierLocation, identifier)) + 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 nullptr; + } +} + +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 NULL; + return nullptr; } } -TIntermAggregate* TParseContext::parseInvariantDeclaration(const TSourceLoc &invariantLoc, +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 aggregateDeclaration; + } + } + else + { + recover(); + 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 declaratorList; + return aggregateDeclaration; } } else { recover(); - return NULL; + 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(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 ¶m = 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; } -TFunction *TParseContext::addConstructorFunc(TPublicType publicType) +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(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 ¶m = 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(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(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(); + const TConstantUnion *unionArray = node->getUnionArrayPointer(); + ASSERT(unionArray); - if (!unionArray) { - return node; - } - } else { // The node has to be either a symbol node or an aggregate node or a tempConstant node, else, its an error - error(line, "Cannot offset into the vector", "Error"); - recover(); - - return 0; - } - - ConstantUnion* constArray = new ConstantUnion[fields.num]; + 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; - } - - 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; + outOfRangeError(outOfRangeIndexIsError, line, "", "[", extraInfo.c_str()); + index = node->getType().getCols() - 1; } - 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(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) +{ + 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(); + *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(node)->getCompleteString(); + extraInfoStream + << "built in unary operator function. Type: " + << static_cast(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& p) : allocator(p.allocator) { } - - template - pool_allocator& operator=(const pool_allocator& p) { - allocator = p.allocator; - return *this; - } + pool_allocator() { } template - pool_allocator(const pool_allocator& p) : allocator(&p.getAllocator()) { } + pool_allocator(const pool_allocator& p) { } + + template + pool_allocator& operator=(const pool_allocator& 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(-1) / sizeof(T); } size_type max_size(int size) const { return static_cast(-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(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 mIndexedVecAndMatrixTypes; + std::set 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 @@ -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 -const std::vector *GetVariableList(const TCompiler *compiler, ShaderVariableType variableType); +const std::vector *GetVariableList(const TCompiler *compiler); template <> -const std::vector *GetVariableList(const TCompiler *compiler, ShaderVariableType) +const std::vector *GetVariableList(const TCompiler *compiler) { return &compiler->getUniforms(); } template <> -const std::vector *GetVariableList(const TCompiler *compiler, ShaderVariableType) +const std::vector *GetVariableList(const TCompiler *compiler) { return &compiler->getVaryings(); } template <> -const std::vector *GetVariableList(const TCompiler *compiler, ShaderVariableType variableType) +const std::vector *GetVariableList(const TCompiler *compiler) +{ + return &compiler->getAttributes(); +} + +template <> +const std::vector *GetVariableList(const TCompiler *compiler) { - return (variableType == SHADERVAR_ATTRIBUTE ? - &compiler->getAttributes() : - &compiler->getOutputVariables()); + return &compiler->getOutputVariables(); } template <> -const std::vector *GetVariableList(const TCompiler *compiler, ShaderVariableType) +const std::vector *GetVariableList(const TCompiler *compiler) { return &compiler->getInterfaceBlocks(); } template -const std::vector *GetShaderVariables(const ShHandle handle, ShaderVariableType variableType) +const std::vector *GetShaderVariables(const ShHandle handle) { if (!handle) { @@ -83,7 +78,7 @@ const std::vector *GetShaderVariables(const ShHandle handle, ShaderVariabl return NULL; } - return GetVariableList(compiler, variableType); + return GetVariableList(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(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 *ShGetNameHashingMap( const std::vector *ShGetUniforms(const ShHandle handle) { - return GetShaderVariables(handle, SHADERVAR_UNIFORM); + return GetShaderVariables(handle); } const std::vector *ShGetVaryings(const ShHandle handle) { - return GetShaderVariables(handle, SHADERVAR_VARYING); + return GetShaderVariables(handle); } const std::vector *ShGetAttributes(const ShHandle handle) { - return GetShaderVariables(handle, SHADERVAR_ATTRIBUTE); + return GetShaderVariables(handle); } -const std::vector *ShGetOutputVariables(const ShHandle handle) +const std::vector *ShGetOutputVariables(const ShHandle handle) { - return GetShaderVariables(handle, SHADERVAR_OUTPUTVARIABLE); + return GetShaderVariables(handle); } const std::vector *ShGetInterfaceBlocks(const ShHandle handle) { - return GetShaderVariables(handle, SHADERVAR_INTERFACEBLOCK); + return GetShaderVariables(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 -#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) {} @@ -304,10 +348,15 @@ 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 #include @@ -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(size)); + case EbtGenIType: return TCache::getType(EbtInt, static_cast(size)); + case EbtGenUType: return TCache::getType(EbtUInt, static_cast(size)); + case EbtGenBType: return TCache::getType(EbtBool, static_cast(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(size)); + case EbtIVec: return TCache::getType(EbtInt, static_cast(size)); + case EbtUVec: return TCache::getType(EbtUInt, static_cast(size)); + case EbtBVec: return TCache::getType(EbtBool, static_cast(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(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 TParamList; + const TString *buildMangledName() const; + + typedef TVector 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(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 mInterfaceBlockRegisterMap; std::map 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, ®isterCount); +} + +void UniformHLSL::outputHLSLSamplerUniformGroup(TInfoSinkBase &out, + const HLSLTextureSamplerGroup textureGroup, + const TVector &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, ®isterCount); + 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> 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 ®isterString = 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 &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"; - case EbtISampler3D: return "Texture3D"; - case EbtISamplerCube: return "Texture2DArray"; - case EbtISampler2DArray: return "Texture2DArray"; - case EbtUSampler2D: return "Texture2D"; - case EbtUSampler3D: return "Texture3D"; - case EbtUSamplerCube: return "Texture2DArray"; - case EbtUSampler2DArray: return "Texture2DArray"; - case EbtSampler2DShadow: return "Texture2D"; - case EbtSamplerCubeShadow: return "TextureCube"; - case EbtSampler2DArrayShadow: return "Texture2DArray"; - default: UNREACHABLE(); + return "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"; + case HLSL_TEXTURE_3D_INT4: + return "Texture3D"; + case HLSL_TEXTURE_2D_ARRAY_INT4: + return "Texture2DArray"; + case HLSL_TEXTURE_2D_UINT4: + return "Texture2D"; + case HLSL_TEXTURE_3D_UINT4: + return "Texture3D"; + case HLSL_TEXTURE_2D_ARRAY_UINT4: + return "Texture2DArray"; + 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 ""; } +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 ""; +} + +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(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(symbol); for (ParamIndex::const_iterator i = pIndex.begin(); i != pIndex.end(); ++i) { - const TParameter ¶m = function->getParam(*i); + const TConstParameter ¶m = 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(type.isArray() ? type.getArraySize() : 1); + const size_t location = static_cast(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 @@ -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 OutputMap; - OutputMap mOutputMap; + typedef std::vector OutputVector; + OutputVector mOutputs; + OutputVector mUnspecifiedLocationOutputs; std::set 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 *attribs, - std::vector *outputVariables, + std::vector *outputVariables, std::vector *uniforms, std::vector *varyings, std::vector *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 *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( + 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( + 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( + 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(); @@ -365,6 +510,26 @@ void CollectVariables::visitVariable(const TIntermSymbol *variable, infoList->push_back(attribute); } +template <> +void CollectVariables::visitVariable(const TIntermSymbol *variable, + std::vector *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(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 *infoList) const @@ -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 *attribs, - std::vector *outputVariables, + std::vector *outputVariables, std::vector *uniforms, std::vector *varyings, std::vector *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 @@ -40,13 +40,14 @@ class CollectVariables : public TIntermTraverser void visitInfoList(const TIntermSequence &sequence, std::vector *infoList) const; std::vector *mAttribs; - std::vector *mOutputVariables; + std::vector *mOutputVariables; std::vector *mUniforms; std::vector *mVaryings; std::vector *mInterfaceBlocks; std::map 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(mCurrentOffset * BytesPerComponent), + static_cast(arrayStride * BytesPerComponent), + static_cast(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 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(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(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 translation_unit function_definition %type statement simple_statement -%type statement_list compound_statement +%type statement_list compound_statement compound_statement_no_new_scope %type declaration_statement selection_statement expression_statement %type declaration external_declaration -%type for_init_statement compound_statement_no_new_scope +%type for_init_statement %type selection_rest_statement for_rest_statement %type switch_statement %type 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 ¶m = 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(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($5.node1), reinterpret_cast($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(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::max(); + *value = std::numeric_limits::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 void traverse(const TType &type, const TString &name, std::vector *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::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 IntT readInt() { - int value; + int value = 0; read(&value); return static_cast(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(); + 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(offset), static_cast(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(destOffset), static_cast(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(offset); mMapLength = static_cast(length); - mAccessFlags = static_cast(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(offset), static_cast(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 Extensions::getStrings() const { std::vector 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 &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 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 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 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 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 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 DisplayExtensions::getStrings() const { std::vector 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 DeviceExtensions::getStrings() const +{ + std::vector 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 ClientExtensions::getStrings() const { std::vector 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 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(mConfigs.size()) + 1; Config copyConfig(config); copyConfig.configID = id; @@ -251,6 +252,9 @@ std::vector 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 +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(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 &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(fenceSync)); + mResourceManager->deleteFenceSync(static_cast(reinterpret_cast(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(handle)); + return mResourceManager->getFenceSync(static_cast(reinterpret_cast(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(const_cast(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(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(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(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(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(mCaps.compressedTextureFormats.size()); } return true; case GL_PROGRAM_BINARY_FORMATS_OES: { *type = GL_INT; - *numParams = mCaps.programBinaryFormats.size(); + *numParams = static_cast(mCaps.programBinaryFormats.size()); } return true; case GL_SHADER_BINARY_FORMATS: { *type = GL_INT; - *numParams = mCaps.shaderBinaryFormats.size(); + *numParams = static_cast(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(param)); break; - case GL_TEXTURE_MAG_FILTER: samplerObject->setMagFilter(static_cast(param)); break; - case GL_TEXTURE_WRAP_S: samplerObject->setWrapS(static_cast(param)); break; - case GL_TEXTURE_WRAP_T: samplerObject->setWrapT(static_cast(param)); break; - case GL_TEXTURE_WRAP_R: samplerObject->setWrapR(static_cast(param)); break; - case GL_TEXTURE_MIN_LOD: samplerObject->setMinLod(static_cast(param)); break; - case GL_TEXTURE_MAX_LOD: samplerObject->setMaxLod(static_cast(param)); break; - case GL_TEXTURE_COMPARE_MODE: samplerObject->setComparisonMode(static_cast(param)); break; - case GL_TEXTURE_COMPARE_FUNC: samplerObject->setComparisonFunc(static_cast(param)); break; - default: UNREACHABLE(); break; + case GL_TEXTURE_MIN_FILTER: samplerObject->setMinFilter(static_cast(param)); break; + case GL_TEXTURE_MAG_FILTER: samplerObject->setMagFilter(static_cast(param)); break; + case GL_TEXTURE_WRAP_S: samplerObject->setWrapS(static_cast(param)); break; + case GL_TEXTURE_WRAP_T: samplerObject->setWrapT(static_cast(param)); break; + case GL_TEXTURE_WRAP_R: samplerObject->setWrapR(static_cast(param)); break; + case GL_TEXTURE_MAX_ANISOTROPY_EXT: samplerObject->setMaxAnisotropy(std::min(static_cast(param), getExtensions().maxTextureAnisotropy)); break; + case GL_TEXTURE_MIN_LOD: samplerObject->setMinLod(static_cast(param)); break; + case GL_TEXTURE_MAX_LOD: samplerObject->setMaxLod(static_cast(param)); break; + case GL_TEXTURE_COMPARE_MODE: samplerObject->setCompareMode(static_cast(param)); break; + case GL_TEXTURE_COMPARE_FUNC: samplerObject->setCompareFunc(static_cast(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(param)); break; - case GL_TEXTURE_MAG_FILTER: samplerObject->setMagFilter(uiround(param)); break; - case GL_TEXTURE_WRAP_S: samplerObject->setWrapS(uiround(param)); break; - case GL_TEXTURE_WRAP_T: samplerObject->setWrapT(uiround(param)); break; - case GL_TEXTURE_WRAP_R: samplerObject->setWrapR(uiround(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(param)); break; - case GL_TEXTURE_COMPARE_FUNC: samplerObject->setComparisonFunc(uiround(param)); break; - default: UNREACHABLE(); break; + case GL_TEXTURE_MIN_FILTER: samplerObject->setMinFilter(uiround(param)); break; + case GL_TEXTURE_MAG_FILTER: samplerObject->setMagFilter(uiround(param)); break; + case GL_TEXTURE_WRAP_S: samplerObject->setWrapS(uiround(param)); break; + case GL_TEXTURE_WRAP_T: samplerObject->setWrapT(uiround(param)); break; + case GL_TEXTURE_WRAP_R: samplerObject->setWrapR(uiround(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(param)); break; + case GL_TEXTURE_COMPARE_FUNC: samplerObject->setCompareFunc(uiround(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(samplerObject->getMinFilter()); - case GL_TEXTURE_MAG_FILTER: return static_cast(samplerObject->getMagFilter()); - case GL_TEXTURE_WRAP_S: return static_cast(samplerObject->getWrapS()); - case GL_TEXTURE_WRAP_T: return static_cast(samplerObject->getWrapT()); - case GL_TEXTURE_WRAP_R: return static_cast(samplerObject->getWrapR()); - case GL_TEXTURE_MIN_LOD: return uiround(samplerObject->getMinLod()); - case GL_TEXTURE_MAX_LOD: return uiround(samplerObject->getMaxLod()); - case GL_TEXTURE_COMPARE_MODE: return static_cast(samplerObject->getComparisonMode()); - case GL_TEXTURE_COMPARE_FUNC: return static_cast(samplerObject->getComparisonFunc()); - default: UNREACHABLE(); return 0; + case GL_TEXTURE_MIN_FILTER: return static_cast(samplerObject->getMinFilter()); + case GL_TEXTURE_MAG_FILTER: return static_cast(samplerObject->getMagFilter()); + case GL_TEXTURE_WRAP_S: return static_cast(samplerObject->getWrapS()); + case GL_TEXTURE_WRAP_T: return static_cast(samplerObject->getWrapT()); + case GL_TEXTURE_WRAP_R: return static_cast(samplerObject->getWrapR()); + case GL_TEXTURE_MAX_ANISOTROPY_EXT: return static_cast(samplerObject->getMaxAnisotropy()); + case GL_TEXTURE_MIN_LOD: return uiround(samplerObject->getMinLod()); + case GL_TEXTURE_MAX_LOD: return uiround(samplerObject->getMaxLod()); + case GL_TEXTURE_COMPARE_MODE: return static_cast(samplerObject->getCompareMode()); + case GL_TEXTURE_COMPARE_FUNC: return static_cast(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(samplerObject->getMinFilter()); - case GL_TEXTURE_MAG_FILTER: return static_cast(samplerObject->getMagFilter()); - case GL_TEXTURE_WRAP_S: return static_cast(samplerObject->getWrapS()); - case GL_TEXTURE_WRAP_T: return static_cast(samplerObject->getWrapT()); - case GL_TEXTURE_WRAP_R: return static_cast(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(samplerObject->getComparisonMode()); - case GL_TEXTURE_COMPARE_FUNC: return static_cast(samplerObject->getComparisonFunc()); - default: UNREACHABLE(); return 0; + case GL_TEXTURE_MIN_FILTER: return static_cast(samplerObject->getMinFilter()); + case GL_TEXTURE_MAG_FILTER: return static_cast(samplerObject->getMagFilter()); + case GL_TEXTURE_WRAP_S: return static_cast(samplerObject->getWrapS()); + case GL_TEXTURE_WRAP_T: return static_cast(samplerObject->getWrapT()); + case GL_TEXTURE_WRAP_R: return static_cast(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(samplerObject->getCompareMode()); + case GL_TEXTURE_COMPARE_FUNC: return static_cast(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(mCaps.maxVertexAttributes, MAX_VERTEX_ATTRIBS); mCaps.maxVertexUniformBlocks = std::min(mCaps.maxVertexUniformBlocks, IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS); @@ -1545,7 +2001,6 @@ void Context::initCaps(GLuint clientVersion) mCaps.maxFragmentInputComponents = std::min(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 mTransformFeedbackZero; typedef std::map 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(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 +#include + +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(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(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(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 &&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 +#include +#include + +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 &&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 ids; + bool enabled; + }; + + struct Group + { + GLenum source; + GLuint id; + std::string message; + + std::vector controls; + }; + + bool mOutputEnabled; + GLDEBUGPROCKHR mCallbackFunction; + const void *mCallbackUserParam; + std::deque mMessages; + GLuint mMaxLoggedMessages; + bool mOutputSynchronous; + std::vector 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 +#include + +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(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(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(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 &&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 +#include +#include + +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 &&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 ids; + bool enabled; + }; + + struct Group + { + GLenum source; + GLuint id; + std::string message; + + std::vector controls; + }; + + bool mOutputEnabled; + GLDEBUGPROCKHR mCallbackFunction; + const void *mCallbackUserParam; + std::deque mMessages; + GLuint mMaxLoggedMessages; + bool mOutputSynchronous; + std::vector 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 + +#include +#include + +#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 +static std::string GenerateExtensionsString(const T &extensions) +{ + std::vector extensionsVector = extensions.getStrings(); + + std::ostringstream stream; + std::copy(extensionsVector.begin(), extensionsVector.end(), std::ostream_iterator(stream, " ")); + return stream.str(); +} + +typedef std::set 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(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 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 DisplayMap; -static DisplayMap *GetDisplayMap() +typedef std::map ANGLEPlatformDisplayMap; +static ANGLEPlatformDisplayMap *GetANGLEPlatformDisplayMap() +{ + static ANGLEPlatformDisplayMap displays; + return &displays; +} + +typedef std::map 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(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(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 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)) != 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 ContextSet; ContextSet mContextSet; + typedef std::set 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 #include +#include 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 mMessage; +}; + +template +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 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/Float16ToFloat32.cpp b/src/3rdparty/angle/src/libANGLE/Float16ToFloat32.cpp deleted file mode 100644 index 5bf7b3fce8..0000000000 --- a/src/3rdparty/angle/src/libANGLE/Float16ToFloat32.cpp +++ /dev/null @@ -1,2203 +0,0 @@ -// -// Copyright (c) 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. -// - -// This file is automatically generated. - -namespace gl -{ - -const static unsigned g_mantissa[2048] = { - 0x00000000, - 0x33800000, - 0x34000000, - 0x34400000, - 0x34800000, - 0x34a00000, - 0x34c00000, - 0x34e00000, - 0x35000000, - 0x35100000, - 0x35200000, - 0x35300000, - 0x35400000, - 0x35500000, - 0x35600000, - 0x35700000, - 0x35800000, - 0x35880000, - 0x35900000, - 0x35980000, - 0x35a00000, - 0x35a80000, - 0x35b00000, - 0x35b80000, - 0x35c00000, - 0x35c80000, - 0x35d00000, - 0x35d80000, - 0x35e00000, - 0x35e80000, - 0x35f00000, - 0x35f80000, - 0x36000000, - 0x36040000, - 0x36080000, - 0x360c0000, - 0x36100000, - 0x36140000, - 0x36180000, - 0x361c0000, - 0x36200000, - 0x36240000, - 0x36280000, - 0x362c0000, - 0x36300000, - 0x36340000, - 0x36380000, - 0x363c0000, - 0x36400000, - 0x36440000, - 0x36480000, - 0x364c0000, - 0x36500000, - 0x36540000, - 0x36580000, - 0x365c0000, - 0x36600000, - 0x36640000, - 0x36680000, - 0x366c0000, - 0x36700000, - 0x36740000, - 0x36780000, - 0x367c0000, - 0x36800000, - 0x36820000, - 0x36840000, - 0x36860000, - 0x36880000, - 0x368a0000, - 0x368c0000, - 0x368e0000, - 0x36900000, - 0x36920000, - 0x36940000, - 0x36960000, - 0x36980000, - 0x369a0000, - 0x369c0000, - 0x369e0000, - 0x36a00000, - 0x36a20000, - 0x36a40000, - 0x36a60000, - 0x36a80000, - 0x36aa0000, - 0x36ac0000, - 0x36ae0000, - 0x36b00000, - 0x36b20000, - 0x36b40000, - 0x36b60000, - 0x36b80000, - 0x36ba0000, - 0x36bc0000, - 0x36be0000, - 0x36c00000, - 0x36c20000, - 0x36c40000, - 0x36c60000, - 0x36c80000, - 0x36ca0000, - 0x36cc0000, - 0x36ce0000, - 0x36d00000, - 0x36d20000, - 0x36d40000, - 0x36d60000, - 0x36d80000, - 0x36da0000, - 0x36dc0000, - 0x36de0000, - 0x36e00000, - 0x36e20000, - 0x36e40000, - 0x36e60000, - 0x36e80000, - 0x36ea0000, - 0x36ec0000, - 0x36ee0000, - 0x36f00000, - 0x36f20000, - 0x36f40000, - 0x36f60000, - 0x36f80000, - 0x36fa0000, - 0x36fc0000, - 0x36fe0000, - 0x37000000, - 0x37010000, - 0x37020000, - 0x37030000, - 0x37040000, - 0x37050000, - 0x37060000, - 0x37070000, - 0x37080000, - 0x37090000, - 0x370a0000, - 0x370b0000, - 0x370c0000, - 0x370d0000, - 0x370e0000, - 0x370f0000, - 0x37100000, - 0x37110000, - 0x37120000, - 0x37130000, - 0x37140000, - 0x37150000, - 0x37160000, - 0x37170000, - 0x37180000, - 0x37190000, - 0x371a0000, - 0x371b0000, - 0x371c0000, - 0x371d0000, - 0x371e0000, - 0x371f0000, - 0x37200000, - 0x37210000, - 0x37220000, - 0x37230000, - 0x37240000, - 0x37250000, - 0x37260000, - 0x37270000, - 0x37280000, - 0x37290000, - 0x372a0000, - 0x372b0000, - 0x372c0000, - 0x372d0000, - 0x372e0000, - 0x372f0000, - 0x37300000, - 0x37310000, - 0x37320000, - 0x37330000, - 0x37340000, - 0x37350000, - 0x37360000, - 0x37370000, - 0x37380000, - 0x37390000, - 0x373a0000, - 0x373b0000, - 0x373c0000, - 0x373d0000, - 0x373e0000, - 0x373f0000, - 0x37400000, - 0x37410000, - 0x37420000, - 0x37430000, - 0x37440000, - 0x37450000, - 0x37460000, - 0x37470000, - 0x37480000, - 0x37490000, - 0x374a0000, - 0x374b0000, - 0x374c0000, - 0x374d0000, - 0x374e0000, - 0x374f0000, - 0x37500000, - 0x37510000, - 0x37520000, - 0x37530000, - 0x37540000, - 0x37550000, - 0x37560000, - 0x37570000, - 0x37580000, - 0x37590000, - 0x375a0000, - 0x375b0000, - 0x375c0000, - 0x375d0000, - 0x375e0000, - 0x375f0000, - 0x37600000, - 0x37610000, - 0x37620000, - 0x37630000, - 0x37640000, - 0x37650000, - 0x37660000, - 0x37670000, - 0x37680000, - 0x37690000, - 0x376a0000, - 0x376b0000, - 0x376c0000, - 0x376d0000, - 0x376e0000, - 0x376f0000, - 0x37700000, - 0x37710000, - 0x37720000, - 0x37730000, - 0x37740000, - 0x37750000, - 0x37760000, - 0x37770000, - 0x37780000, - 0x37790000, - 0x377a0000, - 0x377b0000, - 0x377c0000, - 0x377d0000, - 0x377e0000, - 0x377f0000, - 0x37800000, - 0x37808000, - 0x37810000, - 0x37818000, - 0x37820000, - 0x37828000, - 0x37830000, - 0x37838000, - 0x37840000, - 0x37848000, - 0x37850000, - 0x37858000, - 0x37860000, - 0x37868000, - 0x37870000, - 0x37878000, - 0x37880000, - 0x37888000, - 0x37890000, - 0x37898000, - 0x378a0000, - 0x378a8000, - 0x378b0000, - 0x378b8000, - 0x378c0000, - 0x378c8000, - 0x378d0000, - 0x378d8000, - 0x378e0000, - 0x378e8000, - 0x378f0000, - 0x378f8000, - 0x37900000, - 0x37908000, - 0x37910000, - 0x37918000, - 0x37920000, - 0x37928000, - 0x37930000, - 0x37938000, - 0x37940000, - 0x37948000, - 0x37950000, - 0x37958000, - 0x37960000, - 0x37968000, - 0x37970000, - 0x37978000, - 0x37980000, - 0x37988000, - 0x37990000, - 0x37998000, - 0x379a0000, - 0x379a8000, - 0x379b0000, - 0x379b8000, - 0x379c0000, - 0x379c8000, - 0x379d0000, - 0x379d8000, - 0x379e0000, - 0x379e8000, - 0x379f0000, - 0x379f8000, - 0x37a00000, - 0x37a08000, - 0x37a10000, - 0x37a18000, - 0x37a20000, - 0x37a28000, - 0x37a30000, - 0x37a38000, - 0x37a40000, - 0x37a48000, - 0x37a50000, - 0x37a58000, - 0x37a60000, - 0x37a68000, - 0x37a70000, - 0x37a78000, - 0x37a80000, - 0x37a88000, - 0x37a90000, - 0x37a98000, - 0x37aa0000, - 0x37aa8000, - 0x37ab0000, - 0x37ab8000, - 0x37ac0000, - 0x37ac8000, - 0x37ad0000, - 0x37ad8000, - 0x37ae0000, - 0x37ae8000, - 0x37af0000, - 0x37af8000, - 0x37b00000, - 0x37b08000, - 0x37b10000, - 0x37b18000, - 0x37b20000, - 0x37b28000, - 0x37b30000, - 0x37b38000, - 0x37b40000, - 0x37b48000, - 0x37b50000, - 0x37b58000, - 0x37b60000, - 0x37b68000, - 0x37b70000, - 0x37b78000, - 0x37b80000, - 0x37b88000, - 0x37b90000, - 0x37b98000, - 0x37ba0000, - 0x37ba8000, - 0x37bb0000, - 0x37bb8000, - 0x37bc0000, - 0x37bc8000, - 0x37bd0000, - 0x37bd8000, - 0x37be0000, - 0x37be8000, - 0x37bf0000, - 0x37bf8000, - 0x37c00000, - 0x37c08000, - 0x37c10000, - 0x37c18000, - 0x37c20000, - 0x37c28000, - 0x37c30000, - 0x37c38000, - 0x37c40000, - 0x37c48000, - 0x37c50000, - 0x37c58000, - 0x37c60000, - 0x37c68000, - 0x37c70000, - 0x37c78000, - 0x37c80000, - 0x37c88000, - 0x37c90000, - 0x37c98000, - 0x37ca0000, - 0x37ca8000, - 0x37cb0000, - 0x37cb8000, - 0x37cc0000, - 0x37cc8000, - 0x37cd0000, - 0x37cd8000, - 0x37ce0000, - 0x37ce8000, - 0x37cf0000, - 0x37cf8000, - 0x37d00000, - 0x37d08000, - 0x37d10000, - 0x37d18000, - 0x37d20000, - 0x37d28000, - 0x37d30000, - 0x37d38000, - 0x37d40000, - 0x37d48000, - 0x37d50000, - 0x37d58000, - 0x37d60000, - 0x37d68000, - 0x37d70000, - 0x37d78000, - 0x37d80000, - 0x37d88000, - 0x37d90000, - 0x37d98000, - 0x37da0000, - 0x37da8000, - 0x37db0000, - 0x37db8000, - 0x37dc0000, - 0x37dc8000, - 0x37dd0000, - 0x37dd8000, - 0x37de0000, - 0x37de8000, - 0x37df0000, - 0x37df8000, - 0x37e00000, - 0x37e08000, - 0x37e10000, - 0x37e18000, - 0x37e20000, - 0x37e28000, - 0x37e30000, - 0x37e38000, - 0x37e40000, - 0x37e48000, - 0x37e50000, - 0x37e58000, - 0x37e60000, - 0x37e68000, - 0x37e70000, - 0x37e78000, - 0x37e80000, - 0x37e88000, - 0x37e90000, - 0x37e98000, - 0x37ea0000, - 0x37ea8000, - 0x37eb0000, - 0x37eb8000, - 0x37ec0000, - 0x37ec8000, - 0x37ed0000, - 0x37ed8000, - 0x37ee0000, - 0x37ee8000, - 0x37ef0000, - 0x37ef8000, - 0x37f00000, - 0x37f08000, - 0x37f10000, - 0x37f18000, - 0x37f20000, - 0x37f28000, - 0x37f30000, - 0x37f38000, - 0x37f40000, - 0x37f48000, - 0x37f50000, - 0x37f58000, - 0x37f60000, - 0x37f68000, - 0x37f70000, - 0x37f78000, - 0x37f80000, - 0x37f88000, - 0x37f90000, - 0x37f98000, - 0x37fa0000, - 0x37fa8000, - 0x37fb0000, - 0x37fb8000, - 0x37fc0000, - 0x37fc8000, - 0x37fd0000, - 0x37fd8000, - 0x37fe0000, - 0x37fe8000, - 0x37ff0000, - 0x37ff8000, - 0x38000000, - 0x38004000, - 0x38008000, - 0x3800c000, - 0x38010000, - 0x38014000, - 0x38018000, - 0x3801c000, - 0x38020000, - 0x38024000, - 0x38028000, - 0x3802c000, - 0x38030000, - 0x38034000, - 0x38038000, - 0x3803c000, - 0x38040000, - 0x38044000, - 0x38048000, - 0x3804c000, - 0x38050000, - 0x38054000, - 0x38058000, - 0x3805c000, - 0x38060000, - 0x38064000, - 0x38068000, - 0x3806c000, - 0x38070000, - 0x38074000, - 0x38078000, - 0x3807c000, - 0x38080000, - 0x38084000, - 0x38088000, - 0x3808c000, - 0x38090000, - 0x38094000, - 0x38098000, - 0x3809c000, - 0x380a0000, - 0x380a4000, - 0x380a8000, - 0x380ac000, - 0x380b0000, - 0x380b4000, - 0x380b8000, - 0x380bc000, - 0x380c0000, - 0x380c4000, - 0x380c8000, - 0x380cc000, - 0x380d0000, - 0x380d4000, - 0x380d8000, - 0x380dc000, - 0x380e0000, - 0x380e4000, - 0x380e8000, - 0x380ec000, - 0x380f0000, - 0x380f4000, - 0x380f8000, - 0x380fc000, - 0x38100000, - 0x38104000, - 0x38108000, - 0x3810c000, - 0x38110000, - 0x38114000, - 0x38118000, - 0x3811c000, - 0x38120000, - 0x38124000, - 0x38128000, - 0x3812c000, - 0x38130000, - 0x38134000, - 0x38138000, - 0x3813c000, - 0x38140000, - 0x38144000, - 0x38148000, - 0x3814c000, - 0x38150000, - 0x38154000, - 0x38158000, - 0x3815c000, - 0x38160000, - 0x38164000, - 0x38168000, - 0x3816c000, - 0x38170000, - 0x38174000, - 0x38178000, - 0x3817c000, - 0x38180000, - 0x38184000, - 0x38188000, - 0x3818c000, - 0x38190000, - 0x38194000, - 0x38198000, - 0x3819c000, - 0x381a0000, - 0x381a4000, - 0x381a8000, - 0x381ac000, - 0x381b0000, - 0x381b4000, - 0x381b8000, - 0x381bc000, - 0x381c0000, - 0x381c4000, - 0x381c8000, - 0x381cc000, - 0x381d0000, - 0x381d4000, - 0x381d8000, - 0x381dc000, - 0x381e0000, - 0x381e4000, - 0x381e8000, - 0x381ec000, - 0x381f0000, - 0x381f4000, - 0x381f8000, - 0x381fc000, - 0x38200000, - 0x38204000, - 0x38208000, - 0x3820c000, - 0x38210000, - 0x38214000, - 0x38218000, - 0x3821c000, - 0x38220000, - 0x38224000, - 0x38228000, - 0x3822c000, - 0x38230000, - 0x38234000, - 0x38238000, - 0x3823c000, - 0x38240000, - 0x38244000, - 0x38248000, - 0x3824c000, - 0x38250000, - 0x38254000, - 0x38258000, - 0x3825c000, - 0x38260000, - 0x38264000, - 0x38268000, - 0x3826c000, - 0x38270000, - 0x38274000, - 0x38278000, - 0x3827c000, - 0x38280000, - 0x38284000, - 0x38288000, - 0x3828c000, - 0x38290000, - 0x38294000, - 0x38298000, - 0x3829c000, - 0x382a0000, - 0x382a4000, - 0x382a8000, - 0x382ac000, - 0x382b0000, - 0x382b4000, - 0x382b8000, - 0x382bc000, - 0x382c0000, - 0x382c4000, - 0x382c8000, - 0x382cc000, - 0x382d0000, - 0x382d4000, - 0x382d8000, - 0x382dc000, - 0x382e0000, - 0x382e4000, - 0x382e8000, - 0x382ec000, - 0x382f0000, - 0x382f4000, - 0x382f8000, - 0x382fc000, - 0x38300000, - 0x38304000, - 0x38308000, - 0x3830c000, - 0x38310000, - 0x38314000, - 0x38318000, - 0x3831c000, - 0x38320000, - 0x38324000, - 0x38328000, - 0x3832c000, - 0x38330000, - 0x38334000, - 0x38338000, - 0x3833c000, - 0x38340000, - 0x38344000, - 0x38348000, - 0x3834c000, - 0x38350000, - 0x38354000, - 0x38358000, - 0x3835c000, - 0x38360000, - 0x38364000, - 0x38368000, - 0x3836c000, - 0x38370000, - 0x38374000, - 0x38378000, - 0x3837c000, - 0x38380000, - 0x38384000, - 0x38388000, - 0x3838c000, - 0x38390000, - 0x38394000, - 0x38398000, - 0x3839c000, - 0x383a0000, - 0x383a4000, - 0x383a8000, - 0x383ac000, - 0x383b0000, - 0x383b4000, - 0x383b8000, - 0x383bc000, - 0x383c0000, - 0x383c4000, - 0x383c8000, - 0x383cc000, - 0x383d0000, - 0x383d4000, - 0x383d8000, - 0x383dc000, - 0x383e0000, - 0x383e4000, - 0x383e8000, - 0x383ec000, - 0x383f0000, - 0x383f4000, - 0x383f8000, - 0x383fc000, - 0x38400000, - 0x38404000, - 0x38408000, - 0x3840c000, - 0x38410000, - 0x38414000, - 0x38418000, - 0x3841c000, - 0x38420000, - 0x38424000, - 0x38428000, - 0x3842c000, - 0x38430000, - 0x38434000, - 0x38438000, - 0x3843c000, - 0x38440000, - 0x38444000, - 0x38448000, - 0x3844c000, - 0x38450000, - 0x38454000, - 0x38458000, - 0x3845c000, - 0x38460000, - 0x38464000, - 0x38468000, - 0x3846c000, - 0x38470000, - 0x38474000, - 0x38478000, - 0x3847c000, - 0x38480000, - 0x38484000, - 0x38488000, - 0x3848c000, - 0x38490000, - 0x38494000, - 0x38498000, - 0x3849c000, - 0x384a0000, - 0x384a4000, - 0x384a8000, - 0x384ac000, - 0x384b0000, - 0x384b4000, - 0x384b8000, - 0x384bc000, - 0x384c0000, - 0x384c4000, - 0x384c8000, - 0x384cc000, - 0x384d0000, - 0x384d4000, - 0x384d8000, - 0x384dc000, - 0x384e0000, - 0x384e4000, - 0x384e8000, - 0x384ec000, - 0x384f0000, - 0x384f4000, - 0x384f8000, - 0x384fc000, - 0x38500000, - 0x38504000, - 0x38508000, - 0x3850c000, - 0x38510000, - 0x38514000, - 0x38518000, - 0x3851c000, - 0x38520000, - 0x38524000, - 0x38528000, - 0x3852c000, - 0x38530000, - 0x38534000, - 0x38538000, - 0x3853c000, - 0x38540000, - 0x38544000, - 0x38548000, - 0x3854c000, - 0x38550000, - 0x38554000, - 0x38558000, - 0x3855c000, - 0x38560000, - 0x38564000, - 0x38568000, - 0x3856c000, - 0x38570000, - 0x38574000, - 0x38578000, - 0x3857c000, - 0x38580000, - 0x38584000, - 0x38588000, - 0x3858c000, - 0x38590000, - 0x38594000, - 0x38598000, - 0x3859c000, - 0x385a0000, - 0x385a4000, - 0x385a8000, - 0x385ac000, - 0x385b0000, - 0x385b4000, - 0x385b8000, - 0x385bc000, - 0x385c0000, - 0x385c4000, - 0x385c8000, - 0x385cc000, - 0x385d0000, - 0x385d4000, - 0x385d8000, - 0x385dc000, - 0x385e0000, - 0x385e4000, - 0x385e8000, - 0x385ec000, - 0x385f0000, - 0x385f4000, - 0x385f8000, - 0x385fc000, - 0x38600000, - 0x38604000, - 0x38608000, - 0x3860c000, - 0x38610000, - 0x38614000, - 0x38618000, - 0x3861c000, - 0x38620000, - 0x38624000, - 0x38628000, - 0x3862c000, - 0x38630000, - 0x38634000, - 0x38638000, - 0x3863c000, - 0x38640000, - 0x38644000, - 0x38648000, - 0x3864c000, - 0x38650000, - 0x38654000, - 0x38658000, - 0x3865c000, - 0x38660000, - 0x38664000, - 0x38668000, - 0x3866c000, - 0x38670000, - 0x38674000, - 0x38678000, - 0x3867c000, - 0x38680000, - 0x38684000, - 0x38688000, - 0x3868c000, - 0x38690000, - 0x38694000, - 0x38698000, - 0x3869c000, - 0x386a0000, - 0x386a4000, - 0x386a8000, - 0x386ac000, - 0x386b0000, - 0x386b4000, - 0x386b8000, - 0x386bc000, - 0x386c0000, - 0x386c4000, - 0x386c8000, - 0x386cc000, - 0x386d0000, - 0x386d4000, - 0x386d8000, - 0x386dc000, - 0x386e0000, - 0x386e4000, - 0x386e8000, - 0x386ec000, - 0x386f0000, - 0x386f4000, - 0x386f8000, - 0x386fc000, - 0x38700000, - 0x38704000, - 0x38708000, - 0x3870c000, - 0x38710000, - 0x38714000, - 0x38718000, - 0x3871c000, - 0x38720000, - 0x38724000, - 0x38728000, - 0x3872c000, - 0x38730000, - 0x38734000, - 0x38738000, - 0x3873c000, - 0x38740000, - 0x38744000, - 0x38748000, - 0x3874c000, - 0x38750000, - 0x38754000, - 0x38758000, - 0x3875c000, - 0x38760000, - 0x38764000, - 0x38768000, - 0x3876c000, - 0x38770000, - 0x38774000, - 0x38778000, - 0x3877c000, - 0x38780000, - 0x38784000, - 0x38788000, - 0x3878c000, - 0x38790000, - 0x38794000, - 0x38798000, - 0x3879c000, - 0x387a0000, - 0x387a4000, - 0x387a8000, - 0x387ac000, - 0x387b0000, - 0x387b4000, - 0x387b8000, - 0x387bc000, - 0x387c0000, - 0x387c4000, - 0x387c8000, - 0x387cc000, - 0x387d0000, - 0x387d4000, - 0x387d8000, - 0x387dc000, - 0x387e0000, - 0x387e4000, - 0x387e8000, - 0x387ec000, - 0x387f0000, - 0x387f4000, - 0x387f8000, - 0x387fc000, - 0x38000000, - 0x38002000, - 0x38004000, - 0x38006000, - 0x38008000, - 0x3800a000, - 0x3800c000, - 0x3800e000, - 0x38010000, - 0x38012000, - 0x38014000, - 0x38016000, - 0x38018000, - 0x3801a000, - 0x3801c000, - 0x3801e000, - 0x38020000, - 0x38022000, - 0x38024000, - 0x38026000, - 0x38028000, - 0x3802a000, - 0x3802c000, - 0x3802e000, - 0x38030000, - 0x38032000, - 0x38034000, - 0x38036000, - 0x38038000, - 0x3803a000, - 0x3803c000, - 0x3803e000, - 0x38040000, - 0x38042000, - 0x38044000, - 0x38046000, - 0x38048000, - 0x3804a000, - 0x3804c000, - 0x3804e000, - 0x38050000, - 0x38052000, - 0x38054000, - 0x38056000, - 0x38058000, - 0x3805a000, - 0x3805c000, - 0x3805e000, - 0x38060000, - 0x38062000, - 0x38064000, - 0x38066000, - 0x38068000, - 0x3806a000, - 0x3806c000, - 0x3806e000, - 0x38070000, - 0x38072000, - 0x38074000, - 0x38076000, - 0x38078000, - 0x3807a000, - 0x3807c000, - 0x3807e000, - 0x38080000, - 0x38082000, - 0x38084000, - 0x38086000, - 0x38088000, - 0x3808a000, - 0x3808c000, - 0x3808e000, - 0x38090000, - 0x38092000, - 0x38094000, - 0x38096000, - 0x38098000, - 0x3809a000, - 0x3809c000, - 0x3809e000, - 0x380a0000, - 0x380a2000, - 0x380a4000, - 0x380a6000, - 0x380a8000, - 0x380aa000, - 0x380ac000, - 0x380ae000, - 0x380b0000, - 0x380b2000, - 0x380b4000, - 0x380b6000, - 0x380b8000, - 0x380ba000, - 0x380bc000, - 0x380be000, - 0x380c0000, - 0x380c2000, - 0x380c4000, - 0x380c6000, - 0x380c8000, - 0x380ca000, - 0x380cc000, - 0x380ce000, - 0x380d0000, - 0x380d2000, - 0x380d4000, - 0x380d6000, - 0x380d8000, - 0x380da000, - 0x380dc000, - 0x380de000, - 0x380e0000, - 0x380e2000, - 0x380e4000, - 0x380e6000, - 0x380e8000, - 0x380ea000, - 0x380ec000, - 0x380ee000, - 0x380f0000, - 0x380f2000, - 0x380f4000, - 0x380f6000, - 0x380f8000, - 0x380fa000, - 0x380fc000, - 0x380fe000, - 0x38100000, - 0x38102000, - 0x38104000, - 0x38106000, - 0x38108000, - 0x3810a000, - 0x3810c000, - 0x3810e000, - 0x38110000, - 0x38112000, - 0x38114000, - 0x38116000, - 0x38118000, - 0x3811a000, - 0x3811c000, - 0x3811e000, - 0x38120000, - 0x38122000, - 0x38124000, - 0x38126000, - 0x38128000, - 0x3812a000, - 0x3812c000, - 0x3812e000, - 0x38130000, - 0x38132000, - 0x38134000, - 0x38136000, - 0x38138000, - 0x3813a000, - 0x3813c000, - 0x3813e000, - 0x38140000, - 0x38142000, - 0x38144000, - 0x38146000, - 0x38148000, - 0x3814a000, - 0x3814c000, - 0x3814e000, - 0x38150000, - 0x38152000, - 0x38154000, - 0x38156000, - 0x38158000, - 0x3815a000, - 0x3815c000, - 0x3815e000, - 0x38160000, - 0x38162000, - 0x38164000, - 0x38166000, - 0x38168000, - 0x3816a000, - 0x3816c000, - 0x3816e000, - 0x38170000, - 0x38172000, - 0x38174000, - 0x38176000, - 0x38178000, - 0x3817a000, - 0x3817c000, - 0x3817e000, - 0x38180000, - 0x38182000, - 0x38184000, - 0x38186000, - 0x38188000, - 0x3818a000, - 0x3818c000, - 0x3818e000, - 0x38190000, - 0x38192000, - 0x38194000, - 0x38196000, - 0x38198000, - 0x3819a000, - 0x3819c000, - 0x3819e000, - 0x381a0000, - 0x381a2000, - 0x381a4000, - 0x381a6000, - 0x381a8000, - 0x381aa000, - 0x381ac000, - 0x381ae000, - 0x381b0000, - 0x381b2000, - 0x381b4000, - 0x381b6000, - 0x381b8000, - 0x381ba000, - 0x381bc000, - 0x381be000, - 0x381c0000, - 0x381c2000, - 0x381c4000, - 0x381c6000, - 0x381c8000, - 0x381ca000, - 0x381cc000, - 0x381ce000, - 0x381d0000, - 0x381d2000, - 0x381d4000, - 0x381d6000, - 0x381d8000, - 0x381da000, - 0x381dc000, - 0x381de000, - 0x381e0000, - 0x381e2000, - 0x381e4000, - 0x381e6000, - 0x381e8000, - 0x381ea000, - 0x381ec000, - 0x381ee000, - 0x381f0000, - 0x381f2000, - 0x381f4000, - 0x381f6000, - 0x381f8000, - 0x381fa000, - 0x381fc000, - 0x381fe000, - 0x38200000, - 0x38202000, - 0x38204000, - 0x38206000, - 0x38208000, - 0x3820a000, - 0x3820c000, - 0x3820e000, - 0x38210000, - 0x38212000, - 0x38214000, - 0x38216000, - 0x38218000, - 0x3821a000, - 0x3821c000, - 0x3821e000, - 0x38220000, - 0x38222000, - 0x38224000, - 0x38226000, - 0x38228000, - 0x3822a000, - 0x3822c000, - 0x3822e000, - 0x38230000, - 0x38232000, - 0x38234000, - 0x38236000, - 0x38238000, - 0x3823a000, - 0x3823c000, - 0x3823e000, - 0x38240000, - 0x38242000, - 0x38244000, - 0x38246000, - 0x38248000, - 0x3824a000, - 0x3824c000, - 0x3824e000, - 0x38250000, - 0x38252000, - 0x38254000, - 0x38256000, - 0x38258000, - 0x3825a000, - 0x3825c000, - 0x3825e000, - 0x38260000, - 0x38262000, - 0x38264000, - 0x38266000, - 0x38268000, - 0x3826a000, - 0x3826c000, - 0x3826e000, - 0x38270000, - 0x38272000, - 0x38274000, - 0x38276000, - 0x38278000, - 0x3827a000, - 0x3827c000, - 0x3827e000, - 0x38280000, - 0x38282000, - 0x38284000, - 0x38286000, - 0x38288000, - 0x3828a000, - 0x3828c000, - 0x3828e000, - 0x38290000, - 0x38292000, - 0x38294000, - 0x38296000, - 0x38298000, - 0x3829a000, - 0x3829c000, - 0x3829e000, - 0x382a0000, - 0x382a2000, - 0x382a4000, - 0x382a6000, - 0x382a8000, - 0x382aa000, - 0x382ac000, - 0x382ae000, - 0x382b0000, - 0x382b2000, - 0x382b4000, - 0x382b6000, - 0x382b8000, - 0x382ba000, - 0x382bc000, - 0x382be000, - 0x382c0000, - 0x382c2000, - 0x382c4000, - 0x382c6000, - 0x382c8000, - 0x382ca000, - 0x382cc000, - 0x382ce000, - 0x382d0000, - 0x382d2000, - 0x382d4000, - 0x382d6000, - 0x382d8000, - 0x382da000, - 0x382dc000, - 0x382de000, - 0x382e0000, - 0x382e2000, - 0x382e4000, - 0x382e6000, - 0x382e8000, - 0x382ea000, - 0x382ec000, - 0x382ee000, - 0x382f0000, - 0x382f2000, - 0x382f4000, - 0x382f6000, - 0x382f8000, - 0x382fa000, - 0x382fc000, - 0x382fe000, - 0x38300000, - 0x38302000, - 0x38304000, - 0x38306000, - 0x38308000, - 0x3830a000, - 0x3830c000, - 0x3830e000, - 0x38310000, - 0x38312000, - 0x38314000, - 0x38316000, - 0x38318000, - 0x3831a000, - 0x3831c000, - 0x3831e000, - 0x38320000, - 0x38322000, - 0x38324000, - 0x38326000, - 0x38328000, - 0x3832a000, - 0x3832c000, - 0x3832e000, - 0x38330000, - 0x38332000, - 0x38334000, - 0x38336000, - 0x38338000, - 0x3833a000, - 0x3833c000, - 0x3833e000, - 0x38340000, - 0x38342000, - 0x38344000, - 0x38346000, - 0x38348000, - 0x3834a000, - 0x3834c000, - 0x3834e000, - 0x38350000, - 0x38352000, - 0x38354000, - 0x38356000, - 0x38358000, - 0x3835a000, - 0x3835c000, - 0x3835e000, - 0x38360000, - 0x38362000, - 0x38364000, - 0x38366000, - 0x38368000, - 0x3836a000, - 0x3836c000, - 0x3836e000, - 0x38370000, - 0x38372000, - 0x38374000, - 0x38376000, - 0x38378000, - 0x3837a000, - 0x3837c000, - 0x3837e000, - 0x38380000, - 0x38382000, - 0x38384000, - 0x38386000, - 0x38388000, - 0x3838a000, - 0x3838c000, - 0x3838e000, - 0x38390000, - 0x38392000, - 0x38394000, - 0x38396000, - 0x38398000, - 0x3839a000, - 0x3839c000, - 0x3839e000, - 0x383a0000, - 0x383a2000, - 0x383a4000, - 0x383a6000, - 0x383a8000, - 0x383aa000, - 0x383ac000, - 0x383ae000, - 0x383b0000, - 0x383b2000, - 0x383b4000, - 0x383b6000, - 0x383b8000, - 0x383ba000, - 0x383bc000, - 0x383be000, - 0x383c0000, - 0x383c2000, - 0x383c4000, - 0x383c6000, - 0x383c8000, - 0x383ca000, - 0x383cc000, - 0x383ce000, - 0x383d0000, - 0x383d2000, - 0x383d4000, - 0x383d6000, - 0x383d8000, - 0x383da000, - 0x383dc000, - 0x383de000, - 0x383e0000, - 0x383e2000, - 0x383e4000, - 0x383e6000, - 0x383e8000, - 0x383ea000, - 0x383ec000, - 0x383ee000, - 0x383f0000, - 0x383f2000, - 0x383f4000, - 0x383f6000, - 0x383f8000, - 0x383fa000, - 0x383fc000, - 0x383fe000, - 0x38400000, - 0x38402000, - 0x38404000, - 0x38406000, - 0x38408000, - 0x3840a000, - 0x3840c000, - 0x3840e000, - 0x38410000, - 0x38412000, - 0x38414000, - 0x38416000, - 0x38418000, - 0x3841a000, - 0x3841c000, - 0x3841e000, - 0x38420000, - 0x38422000, - 0x38424000, - 0x38426000, - 0x38428000, - 0x3842a000, - 0x3842c000, - 0x3842e000, - 0x38430000, - 0x38432000, - 0x38434000, - 0x38436000, - 0x38438000, - 0x3843a000, - 0x3843c000, - 0x3843e000, - 0x38440000, - 0x38442000, - 0x38444000, - 0x38446000, - 0x38448000, - 0x3844a000, - 0x3844c000, - 0x3844e000, - 0x38450000, - 0x38452000, - 0x38454000, - 0x38456000, - 0x38458000, - 0x3845a000, - 0x3845c000, - 0x3845e000, - 0x38460000, - 0x38462000, - 0x38464000, - 0x38466000, - 0x38468000, - 0x3846a000, - 0x3846c000, - 0x3846e000, - 0x38470000, - 0x38472000, - 0x38474000, - 0x38476000, - 0x38478000, - 0x3847a000, - 0x3847c000, - 0x3847e000, - 0x38480000, - 0x38482000, - 0x38484000, - 0x38486000, - 0x38488000, - 0x3848a000, - 0x3848c000, - 0x3848e000, - 0x38490000, - 0x38492000, - 0x38494000, - 0x38496000, - 0x38498000, - 0x3849a000, - 0x3849c000, - 0x3849e000, - 0x384a0000, - 0x384a2000, - 0x384a4000, - 0x384a6000, - 0x384a8000, - 0x384aa000, - 0x384ac000, - 0x384ae000, - 0x384b0000, - 0x384b2000, - 0x384b4000, - 0x384b6000, - 0x384b8000, - 0x384ba000, - 0x384bc000, - 0x384be000, - 0x384c0000, - 0x384c2000, - 0x384c4000, - 0x384c6000, - 0x384c8000, - 0x384ca000, - 0x384cc000, - 0x384ce000, - 0x384d0000, - 0x384d2000, - 0x384d4000, - 0x384d6000, - 0x384d8000, - 0x384da000, - 0x384dc000, - 0x384de000, - 0x384e0000, - 0x384e2000, - 0x384e4000, - 0x384e6000, - 0x384e8000, - 0x384ea000, - 0x384ec000, - 0x384ee000, - 0x384f0000, - 0x384f2000, - 0x384f4000, - 0x384f6000, - 0x384f8000, - 0x384fa000, - 0x384fc000, - 0x384fe000, - 0x38500000, - 0x38502000, - 0x38504000, - 0x38506000, - 0x38508000, - 0x3850a000, - 0x3850c000, - 0x3850e000, - 0x38510000, - 0x38512000, - 0x38514000, - 0x38516000, - 0x38518000, - 0x3851a000, - 0x3851c000, - 0x3851e000, - 0x38520000, - 0x38522000, - 0x38524000, - 0x38526000, - 0x38528000, - 0x3852a000, - 0x3852c000, - 0x3852e000, - 0x38530000, - 0x38532000, - 0x38534000, - 0x38536000, - 0x38538000, - 0x3853a000, - 0x3853c000, - 0x3853e000, - 0x38540000, - 0x38542000, - 0x38544000, - 0x38546000, - 0x38548000, - 0x3854a000, - 0x3854c000, - 0x3854e000, - 0x38550000, - 0x38552000, - 0x38554000, - 0x38556000, - 0x38558000, - 0x3855a000, - 0x3855c000, - 0x3855e000, - 0x38560000, - 0x38562000, - 0x38564000, - 0x38566000, - 0x38568000, - 0x3856a000, - 0x3856c000, - 0x3856e000, - 0x38570000, - 0x38572000, - 0x38574000, - 0x38576000, - 0x38578000, - 0x3857a000, - 0x3857c000, - 0x3857e000, - 0x38580000, - 0x38582000, - 0x38584000, - 0x38586000, - 0x38588000, - 0x3858a000, - 0x3858c000, - 0x3858e000, - 0x38590000, - 0x38592000, - 0x38594000, - 0x38596000, - 0x38598000, - 0x3859a000, - 0x3859c000, - 0x3859e000, - 0x385a0000, - 0x385a2000, - 0x385a4000, - 0x385a6000, - 0x385a8000, - 0x385aa000, - 0x385ac000, - 0x385ae000, - 0x385b0000, - 0x385b2000, - 0x385b4000, - 0x385b6000, - 0x385b8000, - 0x385ba000, - 0x385bc000, - 0x385be000, - 0x385c0000, - 0x385c2000, - 0x385c4000, - 0x385c6000, - 0x385c8000, - 0x385ca000, - 0x385cc000, - 0x385ce000, - 0x385d0000, - 0x385d2000, - 0x385d4000, - 0x385d6000, - 0x385d8000, - 0x385da000, - 0x385dc000, - 0x385de000, - 0x385e0000, - 0x385e2000, - 0x385e4000, - 0x385e6000, - 0x385e8000, - 0x385ea000, - 0x385ec000, - 0x385ee000, - 0x385f0000, - 0x385f2000, - 0x385f4000, - 0x385f6000, - 0x385f8000, - 0x385fa000, - 0x385fc000, - 0x385fe000, - 0x38600000, - 0x38602000, - 0x38604000, - 0x38606000, - 0x38608000, - 0x3860a000, - 0x3860c000, - 0x3860e000, - 0x38610000, - 0x38612000, - 0x38614000, - 0x38616000, - 0x38618000, - 0x3861a000, - 0x3861c000, - 0x3861e000, - 0x38620000, - 0x38622000, - 0x38624000, - 0x38626000, - 0x38628000, - 0x3862a000, - 0x3862c000, - 0x3862e000, - 0x38630000, - 0x38632000, - 0x38634000, - 0x38636000, - 0x38638000, - 0x3863a000, - 0x3863c000, - 0x3863e000, - 0x38640000, - 0x38642000, - 0x38644000, - 0x38646000, - 0x38648000, - 0x3864a000, - 0x3864c000, - 0x3864e000, - 0x38650000, - 0x38652000, - 0x38654000, - 0x38656000, - 0x38658000, - 0x3865a000, - 0x3865c000, - 0x3865e000, - 0x38660000, - 0x38662000, - 0x38664000, - 0x38666000, - 0x38668000, - 0x3866a000, - 0x3866c000, - 0x3866e000, - 0x38670000, - 0x38672000, - 0x38674000, - 0x38676000, - 0x38678000, - 0x3867a000, - 0x3867c000, - 0x3867e000, - 0x38680000, - 0x38682000, - 0x38684000, - 0x38686000, - 0x38688000, - 0x3868a000, - 0x3868c000, - 0x3868e000, - 0x38690000, - 0x38692000, - 0x38694000, - 0x38696000, - 0x38698000, - 0x3869a000, - 0x3869c000, - 0x3869e000, - 0x386a0000, - 0x386a2000, - 0x386a4000, - 0x386a6000, - 0x386a8000, - 0x386aa000, - 0x386ac000, - 0x386ae000, - 0x386b0000, - 0x386b2000, - 0x386b4000, - 0x386b6000, - 0x386b8000, - 0x386ba000, - 0x386bc000, - 0x386be000, - 0x386c0000, - 0x386c2000, - 0x386c4000, - 0x386c6000, - 0x386c8000, - 0x386ca000, - 0x386cc000, - 0x386ce000, - 0x386d0000, - 0x386d2000, - 0x386d4000, - 0x386d6000, - 0x386d8000, - 0x386da000, - 0x386dc000, - 0x386de000, - 0x386e0000, - 0x386e2000, - 0x386e4000, - 0x386e6000, - 0x386e8000, - 0x386ea000, - 0x386ec000, - 0x386ee000, - 0x386f0000, - 0x386f2000, - 0x386f4000, - 0x386f6000, - 0x386f8000, - 0x386fa000, - 0x386fc000, - 0x386fe000, - 0x38700000, - 0x38702000, - 0x38704000, - 0x38706000, - 0x38708000, - 0x3870a000, - 0x3870c000, - 0x3870e000, - 0x38710000, - 0x38712000, - 0x38714000, - 0x38716000, - 0x38718000, - 0x3871a000, - 0x3871c000, - 0x3871e000, - 0x38720000, - 0x38722000, - 0x38724000, - 0x38726000, - 0x38728000, - 0x3872a000, - 0x3872c000, - 0x3872e000, - 0x38730000, - 0x38732000, - 0x38734000, - 0x38736000, - 0x38738000, - 0x3873a000, - 0x3873c000, - 0x3873e000, - 0x38740000, - 0x38742000, - 0x38744000, - 0x38746000, - 0x38748000, - 0x3874a000, - 0x3874c000, - 0x3874e000, - 0x38750000, - 0x38752000, - 0x38754000, - 0x38756000, - 0x38758000, - 0x3875a000, - 0x3875c000, - 0x3875e000, - 0x38760000, - 0x38762000, - 0x38764000, - 0x38766000, - 0x38768000, - 0x3876a000, - 0x3876c000, - 0x3876e000, - 0x38770000, - 0x38772000, - 0x38774000, - 0x38776000, - 0x38778000, - 0x3877a000, - 0x3877c000, - 0x3877e000, - 0x38780000, - 0x38782000, - 0x38784000, - 0x38786000, - 0x38788000, - 0x3878a000, - 0x3878c000, - 0x3878e000, - 0x38790000, - 0x38792000, - 0x38794000, - 0x38796000, - 0x38798000, - 0x3879a000, - 0x3879c000, - 0x3879e000, - 0x387a0000, - 0x387a2000, - 0x387a4000, - 0x387a6000, - 0x387a8000, - 0x387aa000, - 0x387ac000, - 0x387ae000, - 0x387b0000, - 0x387b2000, - 0x387b4000, - 0x387b6000, - 0x387b8000, - 0x387ba000, - 0x387bc000, - 0x387be000, - 0x387c0000, - 0x387c2000, - 0x387c4000, - 0x387c6000, - 0x387c8000, - 0x387ca000, - 0x387cc000, - 0x387ce000, - 0x387d0000, - 0x387d2000, - 0x387d4000, - 0x387d6000, - 0x387d8000, - 0x387da000, - 0x387dc000, - 0x387de000, - 0x387e0000, - 0x387e2000, - 0x387e4000, - 0x387e6000, - 0x387e8000, - 0x387ea000, - 0x387ec000, - 0x387ee000, - 0x387f0000, - 0x387f2000, - 0x387f4000, - 0x387f6000, - 0x387f8000, - 0x387fa000, - 0x387fc000, - 0x387fe000, -}; - -const static unsigned g_exponent[64] = { - 0x00000000, - 0x00800000, - 0x01000000, - 0x01800000, - 0x02000000, - 0x02800000, - 0x03000000, - 0x03800000, - 0x04000000, - 0x04800000, - 0x05000000, - 0x05800000, - 0x06000000, - 0x06800000, - 0x07000000, - 0x07800000, - 0x08000000, - 0x08800000, - 0x09000000, - 0x09800000, - 0x0a000000, - 0x0a800000, - 0x0b000000, - 0x0b800000, - 0x0c000000, - 0x0c800000, - 0x0d000000, - 0x0d800000, - 0x0e000000, - 0x0e800000, - 0x0f000000, - 0x47800000, - 0x80000000, - 0x80800000, - 0x81000000, - 0x81800000, - 0x82000000, - 0x82800000, - 0x83000000, - 0x83800000, - 0x84000000, - 0x84800000, - 0x85000000, - 0x85800000, - 0x86000000, - 0x86800000, - 0x87000000, - 0x87800000, - 0x88000000, - 0x88800000, - 0x89000000, - 0x89800000, - 0x8a000000, - 0x8a800000, - 0x8b000000, - 0x8b800000, - 0x8c000000, - 0x8c800000, - 0x8d000000, - 0x8d800000, - 0x8e000000, - 0x8e800000, - 0x8f000000, - 0xc7800000, -}; - -const static unsigned g_offset[64] = { - 0x00000000, - 0x00000400, - 0x00000400, - 0x00000400, - 0x00000400, - 0x00000400, - 0x00000400, - 0x00000400, - 0x00000400, - 0x00000400, - 0x00000400, - 0x00000400, - 0x00000400, - 0x00000400, - 0x00000400, - 0x00000400, - 0x00000400, - 0x00000400, - 0x00000400, - 0x00000400, - 0x00000400, - 0x00000400, - 0x00000400, - 0x00000400, - 0x00000400, - 0x00000400, - 0x00000400, - 0x00000400, - 0x00000400, - 0x00000400, - 0x00000400, - 0x00000400, - 0x00000000, - 0x00000400, - 0x00000400, - 0x00000400, - 0x00000400, - 0x00000400, - 0x00000400, - 0x00000400, - 0x00000400, - 0x00000400, - 0x00000400, - 0x00000400, - 0x00000400, - 0x00000400, - 0x00000400, - 0x00000400, - 0x00000400, - 0x00000400, - 0x00000400, - 0x00000400, - 0x00000400, - 0x00000400, - 0x00000400, - 0x00000400, - 0x00000400, - 0x00000400, - 0x00000400, - 0x00000400, - 0x00000400, - 0x00000400, - 0x00000400, - 0x00000400, -}; - -float float16ToFloat32(unsigned short h) -{ - unsigned i32 = g_mantissa[g_offset[h >> 10] + (h & 0x3ff)] + g_exponent[h >> 10]; - return *(float*) &i32; -} -} - 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(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 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 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 &getDrawBufferStates() const { return mDrawBufferStates; } + GLenum getReadBufferState() const { return mReadBufferState; } + const std::vector &getColorAttachments() const { return mColorAttachments; } + + bool attachmentsHaveSameDimensions() const; - AttachmentList mColorAttachments; - FramebufferAttachment *mDepthAttachment; - FramebufferAttachment *mStencilAttachment; + private: + friend class Framebuffer; + + std::string mLabel; + + std::vector mColorAttachments; + FramebufferAttachment mDepthAttachment; + FramebufferAttachment mStencilAttachment; std::vector 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 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(mResource); } -const ImageIndex *DefaultAttachment::getTextureImageIndex() const +Renderbuffer *FramebufferAttachment::getRenderbuffer() const { - UNREACHABLE(); - return NULL; + return rx::GetAs(mResource); } -Renderbuffer *DefaultAttachment::getRenderbuffer() const +const egl::Surface *FramebufferAttachment::getSurface() const { - UNREACHABLE(); - return NULL; + return rx::GetAs(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 + 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(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 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 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 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::max() - 1)); + mUnallocatedList.push_back(HandleRange(1, std::numeric_limits::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 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(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(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 + +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 mSourcesOf; + BindingPointer 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 mSource; + std::set 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(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(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(minMip, maxMip), - rx::Range(ImageIndex::ENTIRE_LEVEL, ImageIndex::ENTIRE_LEVEL), NULL); + return ImageIndexIterator(GL_TEXTURE_2D, Range(minMip, maxMip), + Range(ImageIndex::ENTIRE_LEVEL, ImageIndex::ENTIRE_LEVEL), NULL); } ImageIndexIterator ImageIndexIterator::MakeCube(GLint minMip, GLint maxMip) { - return ImageIndexIterator(GL_TEXTURE_CUBE_MAP, rx::Range(minMip, maxMip), rx::Range(0, 6), NULL); + return ImageIndexIterator(GL_TEXTURE_CUBE_MAP, Range(minMip, maxMip), Range(0, 6), NULL); } ImageIndexIterator ImageIndexIterator::Make3D(GLint minMip, GLint maxMip, GLint minLayer, GLint maxLayer) { - return ImageIndexIterator(GL_TEXTURE_3D, rx::Range(minMip, maxMip), rx::Range(minLayer, maxLayer), NULL); + return ImageIndexIterator(GL_TEXTURE_3D, Range(minMip, maxMip), Range(minLayer, maxLayer), NULL); } ImageIndexIterator ImageIndexIterator::Make2DArray(GLint minMip, GLint maxMip, const GLsizei *layerCounts) { - return ImageIndexIterator(GL_TEXTURE_2D_ARRAY, rx::Range(minMip, maxMip), - rx::Range(0, IMPLEMENTATION_MAX_2D_ARRAY_TEXTURE_LAYERS), layerCounts); + return ImageIndexIterator(GL_TEXTURE_2D_ARRAY, Range(minMip, maxMip), + Range(0, IMPLEMENTATION_MAX_2D_ARRAY_TEXTURE_LAYERS), layerCounts); } -ImageIndexIterator::ImageIndexIterator(GLenum type, const rx::Range &mipRange, - const rx::Range &layerRange, const GLsizei *layerCounts) +ImageIndexIterator::ImageIndexIterator(GLenum type, const Range &mipRange, + const Range &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 &mipRange, - const rx::Range &layerRange, const GLsizei *layerCounts); + ImageIndexIterator(GLenum type, const Range &mipRange, + const Range &layerRange, const GLsizei *layerCounts); GLint maxLayer() const; GLenum mType; - rx::Range mMipRange; - rx::Range mLayerRange; + Range mMipRange; + Range 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 + +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 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..748ceae030 100644 --- a/src/3rdparty/angle/src/libANGLE/Program.cpp +++ b/src/3rdparty/angle/src/libANGLE/Program.cpp @@ -11,6 +11,7 @@ #include +#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(); + var->precision = stream->readInt(); + var->name = stream->readString(); + var->mappedName = stream->readString(); + var->arraySize = stream->readInt(); + var->staticUse = stream->readBool(); + var->structName = stream->readString(); +} + +// This simplified cast function doesn't need to worry about advanced concepts like +// depth range values, or casting to bool. +template +DestT UniformStateQueryCast(SrcT value); + +// From-Float-To-Integer Casts +template <> +GLint UniformStateQueryCast(GLfloat value) +{ + return clampCast(roundf(value)); +} - return subscript; +template <> +GLuint UniformStateQueryCast(GLfloat value) +{ + return clampCast(roundf(value)); } +// From-Integer-to-Integer Casts +template <> +GLint UniformStateQueryCast(GLuint value) +{ + return clampCast(value); } -AttributeBindings::AttributeBindings() +template <> +GLuint UniformStateQueryCast(GLint value) { + return clampCast(value); } -AttributeBindings::~AttributeBindings() +// From-Boolean-to-Anything Casts +template <> +GLfloat UniformStateQueryCast(GLboolean value) { + return (value == GL_TRUE ? 1.0f : 0.0f); } -InfoLog::InfoLog() : mInfoLog(NULL) +template <> +GLint UniformStateQueryCast(GLboolean value) { + return (value == GL_TRUE ? 1 : 0); } -InfoLog::~InfoLog() +template <> +GLuint UniformStateQueryCast(GLboolean value) { - delete[] mInfoLog; + return (value == GL_TRUE ? 1u : 0u); } +// Default to static_cast +template +DestT UniformStateQueryCast(SrcT value) +{ + return static_cast(value); +} -int InfoLog::getLength() const +template +void UniformStateQueryCastLoop(DestT *dataOut, const uint8_t *srcPointer, int components) { - if (!mInfoLog) + 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(&srcPointer[offset]); + dataOut[comp] = UniformStateQueryCast(*typedSrcPointer); } - else +} + +bool UniformInList(const std::vector &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() +{ } -void InfoLog::getLog(GLsizei bufSize, GLsizei *length, char *infoLog) +InfoLog::InfoLog() { - int index = 0; +} + +InfoLog::~InfoLog() +{ +} + +size_t InfoLog::getLength() const +{ + 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(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(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) +{ +} + +VariableLocation::VariableLocation(const std::string &name, unsigned int element, unsigned int index) + : name(name), + element(element), + index(index) +{ +} - char *logPointer = NULL; +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(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(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 linkedVaryings; - rx::LinkResult result = mProgram->link(data, mInfoLog, mFragmentShader, mVertexShader, mTransformFeedbackVaryings, mTransformFeedbackBufferMode, - ®isters, &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(); - 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 minorVersion = stream.readInt(); 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 int attribCount = stream.readInt(); + ASSERT(mData.mAttributes.empty()); + for (unsigned int attribIndex = 0; attribIndex < attribCount; ++attribIndex) + { + sh::Attribute attrib; + LoadShaderVar(&stream, &attrib); + attrib.location = stream.readInt(); + mData.mAttributes.push_back(attrib); + } + + unsigned int uniformCount = stream.readInt(); + ASSERT(mData.mUniforms.empty()); + for (unsigned int uniformIndex = 0; uniformIndex < uniformCount; ++uniformIndex) + { + LinkedUniform uniform; + LoadShaderVar(&stream, &uniform); + + uniform.blockIndex = stream.readInt(); + uniform.blockInfo.offset = stream.readInt(); + uniform.blockInfo.arrayStride = stream.readInt(); + uniform.blockInfo.matrixStride = stream.readInt(); + uniform.blockInfo.isRowMajorMatrix = stream.readBool(); + + mData.mUniforms.push_back(uniform); + } + + const unsigned int uniformIndexCount = stream.readInt(); + 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(); + 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(); + for (unsigned int blockMemberIndex = 0; blockMemberIndex < numMembers; blockMemberIndex++) + { + uniformBlock.memberUniformIndexes.push_back(stream.readInt()); + } + + mData.mUniformBlocks.push_back(uniformBlock); + } + + unsigned int transformFeedbackVaryingCount = stream.readInt(); + ASSERT(mData.mTransformFeedbackVaryingVars.empty()); + for (unsigned int transformFeedbackVaryingIndex = 0; + transformFeedbackVaryingIndex < transformFeedbackVaryingCount; + ++transformFeedbackVaryingIndex) { - 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]); + 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(); + for (unsigned int outputIndex = 0; outputIndex < outputVarCount; ++outputIndex) + { + int locationIndex = stream.readInt(); + 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(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.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(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.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(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::max(), &length); + Error error = saveBinary(nullptr, nullptr, std::numeric_limits::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(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(-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(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(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(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(locationIt->first); + return static_cast(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(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(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(maxLength); } GLint Program::getActiveUniformi(GLuint index, GLenum pname) const { - const gl::LinkedUniform& uniform = *mProgram->getUniforms()[index]; + ASSERT(static_cast(index) < mData.mUniforms.size()); + const gl::LinkedUniform &uniform = mData.mUniforms[index]; switch (pname) { case GL_UNIFORM_TYPE: return static_cast(uniform.type); @@ -851,159 +1114,165 @@ GLint Program::getActiveUniformi(GLuint index, GLenum pname) const bool Program::isValidUniformLocation(GLint location) const { - ASSERT(rx::IsIntegerCastSafe(mProgram->getUniformIndices().size())); - return (location >= 0 && location < static_cast(mProgram->getUniformIndices().size())); -} - -LinkedUniform *Program::getUniformByLocation(GLint location) const -{ - return mProgram->getUniformByLocation(location); + ASSERT(rx::IsIntegerCastSafe(mData.mUniformLocations.size())); + return (location >= 0 && static_cast(location) < mData.mUniformLocations.size()); } -LinkedUniform *Program::getUniformByName(const std::string &name) const +const LinkedUniform &Program::getUniformByLocation(GLint location) const { - return mProgram->getUniformByName(name); + ASSERT(location >= 0 && static_cast(location) < mData.mUniformLocations.size()); + return mData.mUniforms[mData.mUniformLocations[location].index]; } -GLint Program::getUniformLocation(const std::string &name) +GLint Program::getUniformLocation(const std::string &name) const { - return mProgram->getUniformLocation(name); + return mData.getUniformLocation(name); } -GLuint Program::getUniformIndex(const std::string &name) +GLuint Program::getUniformIndex(const std::string &name) const { - 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) -{ - mProgram->getUniformiv(location, v); -} - -void Program::getUniformuiv(GLint location, GLuint *v) +void Program::getUniformfv(GLint location, GLfloat *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::getUniformiv(GLint location, GLint *v) const { - return mProgram->applyUniforms(); + getUniformInternal(location, v); } -Error Program::applyUniformBuffers(const gl::Data &data) +void Program::getUniformuiv(GLint location, GLuint *v) const { - return mProgram->applyUniformBuffers(data, mUniformBlockBindings); + getUniformInternal(location, v); } void Program::flagForDeletion() @@ -1019,52 +1288,117 @@ 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(); + } -bool Program::isValidated() const -{ - return mValidated; + 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(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; } -void Program::updateSamplerMapping() +bool Program::isValidated() const { - return mProgram->updateSamplerMapping(); + return mValidated; } -GLuint Program::getActiveUniformBlockCount() +GLuint Program::getActiveUniformBlockCount() const { - return mProgram->getUniformBlocks().size(); + return static_cast(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(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(uniformBlock.dataSize); break; case GL_UNIFORM_BLOCK_NAME_LENGTH: - *params = static_cast(uniformBlock.name.size() + 1 + (uniformBlock.isArrayElement() ? 3 : 0)); + *params = + static_cast(uniformBlock.name.size() + 1 + (uniformBlock.isArray ? 3 : 0)); break; case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS: *params = static_cast(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(uniformBlock.isReferencedByVertexShader()); + *params = static_cast(uniformBlock.vertexStaticUse); break; case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER: - *params = static_cast(uniformBlock.isReferencedByFragmentShader()); + *params = static_cast(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(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(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(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(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(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(mProgram->getTransformFeedbackLinkedVaryings().size()); + return static_cast(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(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 &fragmentVaryings = fragmentShader->getVaryings(); - std::vector &vertexVaryings = vertexShader->getVaryings(); + const std::vector &vertexVaryings = vertexShader->getVaryings(); + const std::vector &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 &vertexUniforms = mData.mAttachedVertexShader->getUniforms(); + const std::vector &fragmentUniforms = mData.mAttachedFragmentShader->getUniforms(); + + // Check that uniforms defined in the vertex and fragment shaders are identical + std::map 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(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 &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 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(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(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 &vertexInterfaceBlocks = vertexShader.getInterfaceBlocks(); const std::vector &fragmentInterfaceBlocks = fragmentShader.getInterfaceBlocks(); + // Check that interface blocks defined in the vertex and fragment shaders are identical typedef std::map 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(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(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 &linkedVaryings, - const std::vector &transformFeedbackVaryingNames, - GLenum transformFeedbackBufferMode, - std::vector *outTransformFeedbackLinkedVaryings, - const Caps &caps) const +bool Program::linkValidateTransformFeedback(InfoLog &infoLog, + const std::vector &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 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); + + if (varying->isArray()) + { + infoLog << "Capture of arrays is undefined and not supported."; + return false; } - size_t componentCount = linkedVaryings[j].semanticIndexCount * 4; - if (transformFeedbackBufferMode == GL_SEPARATE_ATTRIBS && + // 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 &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 Program::getMergedVaryings() const +{ + std::set uniqueNames; + std::vector 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 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(mData.mUniforms.size()); + mSamplerUniformRange.end = + mSamplerUniformRange.start + static_cast(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 *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 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 +void Program::defineUniformBlockMembers(const std::vector &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(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 blockUniformIndexes; + for (size_t blockUniformIndex = firstBlockUniformIndex; + blockUniformIndex < lastBlockUniformIndex; ++blockUniformIndex) + { + blockUniformIndexes.push_back(static_cast(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(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(blockSize); + mData.mUniformBlocks.push_back(block); + } +} + +template +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(destPointer); + for (GLsizei component = 0; component < count; ++component) + { + destAsInt[component] = (v[component] != static_cast(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 +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(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 +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::value) + { + memcpy(dataOut, srcPointer, uniform.getElementSize()); + return; + } + + int components = VariableComponentCount(uniform.type) * uniform.elementCount(); + + switch (componentType) + { + case GL_INT: + UniformStateQueryCastLoop(dataOut, srcPointer, components); + break; + case GL_UNSIGNED_INT: + UniformStateQueryCastLoop(dataOut, srcPointer, components); + break; + case GL_BOOL: + UniformStateQueryCastLoop(dataOut, srcPointer, components); + break; + case GL_FLOAT: + UniformStateQueryCastLoop(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 #include -#include -#include #include +#include +#include +#include + +#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 + 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 + 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 &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 &getAttributes() const { return mAttributes; } + const AttributesMask &getActiveAttribLocationsMask() const + { + return mActiveAttribLocationsMask; + } + const std::map &getOutputVariables() const + { + return mOutputVariables; + } + const std::vector &getUniforms() const { return mUniforms; } + const std::vector &getUniformLocations() const + { + return mUniformLocations; + } + const std::vector &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 mTransformFeedbackVaryingNames; + std::vector mTransformFeedbackVaryingVars; + GLenum mTransformFeedbackBufferMode; + + GLuint mUniformBlockBindings[IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS]; + UniformBlockBindingMask mActiveUniformBlockBindings; + + std::vector mAttributes; + std::bitset 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 mUniforms; + std::vector mUniformLocations; + std::vector mUniformBlocks; + + // TODO(jmadill): use unordered/hash map when available + std::map 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 &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 &linkedVaryings, - const std::vector &transformFeedbackVaryingNames, - GLenum transformFeedbackBufferMode, - std::vector *outTransformFeedbackLinkedVaryings, - const Caps &caps) const; + bool linkValidateTransformFeedback(InfoLog &infoLog, + const std::vector &linkedVaryings, + const Caps &caps) const; + + void gatherTransformFeedbackVaryings(const std::vector &varyings); bool assignUniformBlockRegister(InfoLog &infoLog, UniformBlock *uniformBlock, GLenum shader, unsigned int registerIndex, const Caps &caps); void defineOutputVariables(Shader *fragmentShader); - rx::ProgramImpl *mProgram; + std::vector getMergedVaryings() const; + void linkOutputVariables(); - sh::Attribute mLinkedAttribute[MAX_VERTEX_ATTRIBS]; + bool flattenUniformsAndCheckCaps(const Caps &caps, InfoLog &infoLog); - std::map 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 *samplerUniforms); + + void gatherInterfaceBlockInfo(); + template + void defineUniformBlockMembers(const std::vector &fields, + const std::string &prefix, + int blockIndex); + + void defineUniformBlock(const sh::InterfaceBlock &interfaceBlock, GLenum shaderType); - GLuint mUniformBlockBindings[IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS]; + template + void setUniformInternal(GLint location, GLsizei count, const T *v); - std::vector mTransformFeedbackVaryings; - GLenum mTransformFeedbackBufferMode; + template + void setMatrixUniformInternal(GLint location, GLsizei count, GLboolean transpose, const T *v); + + template + 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 mCachedValidateSamplersResult; + std::vector 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 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 &other) const + { + return mObject == other.mObject; + } + + bool operator!=(const BindingPointer &other) const { return !(*this == other); } private: ObjectType *mObject; @@ -102,6 +121,16 @@ class OffsetBindingPointer : public BindingPointer GLintptr getOffset() const { return mOffset; } GLsizeiptr getSize() const { return mSize; } + bool operator==(const OffsetBindingPointer &other) const + { + return this->get() == other.get() && mOffset == other.mOffset && mSize == other.mSize; + } + + bool operator!=(const OffsetBindingPointer &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(width); + mHeight = static_cast(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(width); + mHeight = static_cast(height); mInternalFormat = internalformat; - mSamples = samples; + mSamples = static_cast(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(image->getWidth()); + mHeight = static_cast(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 + +#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 +std::vector GetActiveShaderVariables(const std::vector *variableList) +{ + ASSERT(variableList); + std::vector 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 +template +const std::vector &GetShaderVariables(const std::vector *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(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(mShader->getInfoLog().length())); - memcpy(infoLog, mShader->getInfoLog().c_str(), index); + index = std::min(bufSize - 1, static_cast(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(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(mData.mTranslatedSource.length()) + 1); +} + +int Shader::getTranslatedSourceWithDebugInfoLength() const +{ + const std::string &debugInfo = mImplementation->getDebugInfo(); + if (debugInfo.empty()) + { + return 0; + } + + return (static_cast(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 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 &Shader::getVaryings() const -{ - return mShader->getVaryings(); -} - -const std::vector &Shader::getUniforms() const -{ - return mShader->getUniforms(); -} - -const std::vector &Shader::getInterfaceBlocks() const +int Shader::getShaderVersion() const { - return mShader->getInterfaceBlocks(); + return mData.mShaderVersion; } -const std::vector &Shader::getActiveAttributes() const +const std::vector &Shader::getVaryings() const { - return mShader->getActiveAttributes(); + return mData.getVaryings(); } -const std::vector &Shader::getActiveOutputVariables() const -{ - return mShader->getActiveOutputVariables(); -} - -std::vector &Shader::getVaryings() -{ - return mShader->getVaryings(); -} - -std::vector &Shader::getUniforms() +const std::vector &Shader::getUniforms() const { - return mShader->getUniforms(); + return mData.getUniforms(); } -std::vector &Shader::getInterfaceBlocks() +const std::vector &Shader::getInterfaceBlocks() const { - return mShader->getInterfaceBlocks(); + return mData.getInterfaceBlocks(); } -std::vector &Shader::getActiveAttributes() +const std::vector &Shader::getActiveAttributes() const { - return mShader->getActiveAttributes(); + return mData.getActiveAttributes(); } -std::vector &Shader::getActiveOutputVariables() +const std::vector &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 &getVaryings() const { return mVaryings; } + const std::vector &getUniforms() const { return mUniforms; } + const std::vector &getInterfaceBlocks() const + { + return mInterfaceBlocks; + } + const std::vector &getActiveAttributes() const { return mActiveAttributes; } + const std::vector &getActiveOutputVariables() const + { + return mActiveOutputVariables; + } + + private: + friend class Shader; + + std::string mLabel; + + GLenum mShaderType; + int mShaderVersion; + std::string mTranslatedSource; + std::string mSource; + + std::vector mVaryings; + std::vector mUniforms; + std::vector mInterfaceBlocks; + std::vector mActiveAttributes; + std::vector 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 &getVaryings() const; + int getShaderVersion() const; + + const std::vector &getVaryings() const; const std::vector &getUniforms() const; const std::vector &getInterfaceBlocks() const; const std::vector &getActiveAttributes() const; - const std::vector &getActiveOutputVariables() const; - - std::vector &getVaryings(); - std::vector &getUniforms(); - std::vector &getInterfaceBlocks(); - std::vector &getActiveAttributes(); - std::vector &getActiveOutputVariables(); + const std::vector &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(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(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(index) < mUniformBuffers.size()); - - return mUniformBuffers[index].id(); -} - -Buffer *State::getIndexedUniformBuffer(GLuint index) const +const OffsetBindingPointer &State::getIndexedUniformBuffer(size_t index) const { ASSERT(static_cast(index) < mUniformBuffers.size()); - - return mUniformBuffers[index].get(); -} - -GLintptr State::getIndexedUniformBufferOffset(GLuint index) const -{ - ASSERT(static_cast(index) < mUniformBuffers.size()); - - return mUniformBuffers[index].getOffset(); -} - -GLsizeiptr State::getIndexedUniformBufferSize(GLuint index) const -{ - ASSERT(static_cast(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(index) < mTransformFeedbackBuffers.size()); - - return mTransformFeedbackBuffers[index].id(); -} - -Buffer *State::getIndexedTransformFeedbackBuffer(GLuint index) const -{ - ASSERT(static_cast(index) < mTransformFeedbackBuffers.size()); - - return mTransformFeedbackBuffers[index].get(); -} - -GLuint State::getIndexedTransformFeedbackBufferOffset(GLuint index) const -{ - ASSERT(static_cast(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 *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(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(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(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(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(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(mActiveSampler), GL_TEXTURE_CUBE_MAP); break; case GL_TEXTURE_BINDING_3D: ASSERT(mActiveSampler < mMaxCombinedTextureImageUnits); - *params = getSamplerTextureId(mActiveSampler, GL_TEXTURE_3D); + *params = getSamplerTextureId(static_cast(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(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(mDebug.getMessageCount()); + break; + case GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH: + *params = static_cast(mDebug.getNextMessageLength()); + break; + case GL_DEBUG_GROUP_STACK_DEPTH: + *params = static_cast(mDebug.getGroupStackDepth()); + break; default: UNREACHABLE(); break; } } +void State::getPointerv(GLenum pname, void **params) const +{ + switch (pname) + { + case GL_DEBUG_CALLBACK_FUNCTION: + *params = reinterpret_cast(mDebug.getCallback()); + break; + case GL_DEBUG_CALLBACK_USER_PARAM: + *params = const_cast(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(index) < mTransformFeedbackBuffers.size()) + if (static_cast(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(index) < mTransformFeedbackBuffers.size()) + if (static_cast(index) < mTransformFeedback->getIndexedBufferCount()) { - *data = mTransformFeedbackBuffers[index].getOffset(); + *data = mTransformFeedback->getIndexedBuffer(index).getOffset(); } break; case GL_TRANSFORM_FEEDBACK_BUFFER_SIZE: - if (static_cast(index) < mTransformFeedbackBuffers.size()) + if (static_cast(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 +#include + #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 > TextureMap; +typedef std::map> 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 &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 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 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 > TextureBindingVector; + typedef std::vector> TextureBindingVector; typedef std::map TextureBindingMap; TextureBindingMap mSamplerTextures; - typedef std::vector< BindingPointer > SamplerBindingVector; + typedef std::vector> SamplerBindingVector; SamplerBindingVector mSamplers; - typedef std::map< GLenum, BindingPointer > ActiveQueryMap; + typedef std::map> ActiveQueryMap; ActiveQueryMap mActiveQueries; BindingPointer mGenericUniformBuffer; - typedef std::vector< OffsetBindingPointer > BufferVector; + typedef std::vector> BufferVector; BufferVector mUniformBuffers; BindingPointer mTransformFeedback; - BindingPointer mGenericTransformFeedbackBuffer; - BufferVector mTransformFeedbackBuffers; BindingPointer mCopyReadBuffer; BindingPointer 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 +#include + 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(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(mFixedWidth) : mImplementation->getWidth(); } EGLint Surface::getHeight() const { - return mFixedSize ? mFixedHeight : mImplementation->getHeight(); + return mFixedSize ? static_cast(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 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(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(levels); level++) { - Extents levelSize(std::max(baseSize.width >> level, 1), - std::max(baseSize.height >> level, 1), - (mTarget == GL_TEXTURE_2D_ARRAY) ? baseSize.depth : std::max(baseSize.depth >> level, 1)); + Extents levelSize( + std::max(baseSize.width >> level, 1), std::max(baseSize.height >> level, 1), + (mTarget == GL_TEXTURE_2D_ARRAY) ? baseSize.depth + : std::max(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(imageTarget->getWidth()), + static_cast(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(expectedMipLevels, samplerState.maxLevel + 1); + size_t maxLevel = std::min(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 +#include + +#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 -#include 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(-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 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 &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 &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 &getGenericBuffer() const; + + void bindIndexedBuffer(size_t index, Buffer *buffer, size_t offset, size_t size); + const OffsetBindingPointer &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 mGenericBuffer; + std::vector> 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(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(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 memberUniformIndexes; + bool vertexStaticUse; + bool fragmentStaticUse; - unsigned int psRegisterIndex; - unsigned int vsRegisterIndex; + std::vector 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 + +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 &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 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 &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 &getElementArrayBuffer() const { return mData.getElementArrayBuffer(); } + size_t getMaxAttribs() const { return mData.getVertexAttributes().size(); } + const std::vector &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 &getElementArrayBuffer() const { return mElementArrayBuffer; } + size_t getMaxAttribs() const { return mVertexAttributes.size(); } + size_t getMaxEnabledAttribute() const { return mMaxEnabledAttribute; } + const std::vector &getVertexAttributes() const { return mVertexAttributes; } + const VertexAttribute &getVertexAttribute(size_t index) const + { + return mVertexAttributes[index]; + } + + private: + friend class VertexArray; + std::string mLabel; + std::vector mVertexAttributes; + BindingPointer 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 DirtyBits; + + void syncImplState(); + bool hasAnyDirtyBit() const { return mDirtyBits.any(); } + private: GLuint mId; rx::VertexArrayImpl *mVertexArray; - std::vector mVertexAttributes; - BindingPointer 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 -T QuerySingleVertexAttributeParameter(const VertexAttribute& attrib, GLenum pname) -{ - switch (pname) - { - case GL_VERTEX_ATTRIB_ARRAY_ENABLED: - return static_cast(attrib.enabled ? GL_TRUE : GL_FALSE); - case GL_VERTEX_ATTRIB_ARRAY_SIZE: - return static_cast(attrib.size); - case GL_VERTEX_ATTRIB_ARRAY_STRIDE: - return static_cast(attrib.stride); - case GL_VERTEX_ATTRIB_ARRAY_TYPE: - return static_cast(attrib.type); - case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED: - return static_cast(attrib.normalized ? GL_TRUE : GL_FALSE); - case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING: - return static_cast(attrib.buffer.id()); - case GL_VERTEX_ATTRIB_ARRAY_DIVISOR: - return static_cast(attrib.divisor); - case GL_VERTEX_ATTRIB_ARRAY_INTEGER: - return static_cast(attrib.pureInteger ? GL_TRUE : GL_FALSE); - default: - UNREACHABLE(); - return static_cast(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 +T QuerySingleVertexAttributeParameter(const VertexAttribute& attrib, GLenum pname) +{ + switch (pname) + { + case GL_VERTEX_ATTRIB_ARRAY_ENABLED: + return static_cast(attrib.enabled ? GL_TRUE : GL_FALSE); + case GL_VERTEX_ATTRIB_ARRAY_SIZE: + return static_cast(attrib.size); + case GL_VERTEX_ATTRIB_ARRAY_STRIDE: + return static_cast(attrib.stride); + case GL_VERTEX_ATTRIB_ARRAY_TYPE: + return static_cast(attrib.type); + case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED: + return static_cast(attrib.normalized ? GL_TRUE : GL_FALSE); + case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING: + return static_cast(attrib.buffer.id()); + case GL_VERTEX_ATTRIB_ARRAY_DIVISOR: + return static_cast(attrib.divisor); + case GL_VERTEX_ATTRIB_ARRAY_INTEGER: + return static_cast(attrib.pureInteger ? GL_TRUE : GL_FALSE); + default: + UNREACHABLE(); + return static_cast(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 &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 -#include + +#include 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 -bool operator==(const Color &a, const Color &b) -{ - return a.red == b.red && - a.green == b.green && - a.blue == b.blue && - a.alpha == b.alpha; -} +bool operator==(const Color &a, const Color &b); template -bool operator!=(const Color &a, const Color &b) -{ - return !(a == b); -} +bool operator!=(const Color &a, const Color &b); typedef Color ColorF; typedef Color ColorI; @@ -62,13 +68,21 @@ typedef Color 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 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 AttributesMask; +// Use in Program +typedef std::bitset 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(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 inline DestT *GetAs(SrcT *src) { - ASSERT(HAS_DYNAMIC_TYPE(DestT*, src)); + ASSERT(ANGLE_HAS_DYNAMIC_TYPE(DestT*, src)); return static_cast(src); } template 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(src); } +#undef ANGLE_HAS_DYNAMIC_TYPE + // Downcast a GL object to an Impl (EG gl::Texture to rx::TextureD3D) template 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 +bool operator==(const Color &a, const Color &b) +{ + return a.red == b.red && + a.green == b.green && + a.blue == b.blue && + a.alpha == b.alpha; +} + +template +bool operator!=(const Color &a, const Color &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 +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(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 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 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 + +#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(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 + #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 -struct CastStateValueEnum { static GLenum mEnumForType; }; +GLint64 ExpandFloatToInteger(GLfloat value) +{ + return static_cast((static_cast(0xFFFFFFFFULL) * value - 1.0) / 2.0); +} -template <> GLenum CastStateValueEnum::mEnumForType = GL_INT; -template <> GLenum CastStateValueEnum::mEnumForType = GL_UNSIGNED_INT; -template <> GLenum CastStateValueEnum::mEnumForType = GL_BOOL; -template <> GLenum CastStateValueEnum::mEnumForType = GL_INT_64_ANGLEX; -template <> GLenum CastStateValueEnum::mEnumForType = GL_FLOAT; +template +QueryT ClampToQueryRange(GLint64 value) +{ + const GLint64 min = static_cast(std::numeric_limits::min()); + const GLint64 max = static_cast(std::numeric_limits::max()); + return static_cast(clamp(value, min, max)); +} template QueryT CastStateValueToInt(GLenum pname, NativeT value) { - GLenum queryType = CastStateValueEnum::mEnumForType; - GLenum nativeType = CastStateValueEnum::mEnumForType; + GLenum queryType = GLTypeToGLenum::value; + GLenum nativeType = GLTypeToGLenum::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((static_cast(0xFFFFFFFF) * value - 1.0f) / 2.0f); + return ClampToQueryRange(ExpandFloatToInteger(static_cast(value))); } else { - return gl::iround(value); + return gl::iround(static_cast(value)); } } @@ -59,77 +66,80 @@ QueryT CastStateValueToInt(GLenum pname, NativeT value) template QueryT CastStateValue(GLenum pname, NativeT value) { - GLenum queryType = CastStateValueEnum::mEnumForType; + GLenum queryType = GLTypeToGLenum::value; switch (queryType) { - case GL_INT: return CastStateValueToInt(pname, value); - case GL_INT_64_ANGLEX: return CastStateValueToInt(pname, value); - case GL_FLOAT: return static_cast(value); - case GL_BOOL: return (value == static_cast(0) ? GL_FALSE : GL_TRUE); - default: UNREACHABLE(); return 0; + case GL_INT: + return CastStateValueToInt(pname, value); + case GL_INT_64_ANGLEX: + return CastStateValueToInt(pname, value); + case GL_FLOAT: + return static_cast(value); + case GL_BOOL: + return static_cast(value == static_cast(0) ? GL_FALSE : GL_TRUE); + default: + UNREACHABLE(); + return 0; } } +} // anonymous namespace + +template <> +GLenum GLTypeToGLenum::value = GL_INT; +template <> +GLenum GLTypeToGLenum::value = GL_UNSIGNED_INT; +template <> +GLenum GLTypeToGLenum::value = GL_BOOL; +template <> +GLenum GLTypeToGLenum::value = GL_INT_64_ANGLEX; +template <> +GLenum GLTypeToGLenum::value = GL_FLOAT; + template 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 intParams(numParams, 0); + context->getIntegerv(pname, intParams.data()); for (unsigned int i = 0; i < numParams; ++i) { outParams[i] = CastStateValue(pname, intParams[i]); } - - delete [] intParams; } else if (nativeType == GL_BOOL) { - GLboolean *boolParams = NULL; - boolParams = new GLboolean[numParams]; - - context->getBooleanv(pname, boolParams); + std::vector 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(0) : static_cast(1)); } - - delete [] boolParams; } else if (nativeType == GL_FLOAT) { - GLfloat *floatParams = NULL; - floatParams = new GLfloat[numParams]; - - context->getFloatv(pname, floatParams); + std::vector floatParams(numParams, 0.0f); + context->getFloatv(pname, floatParams.data()); for (unsigned int i = 0; i < numParams; ++i) { outParams[i] = CastStateValue(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 int64Params(numParams, 0); + context->getInteger64v(pname, int64Params.data()); for (unsigned int i = 0; i < numParams; ++i) { outParams[i] = CastStateValue(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 +struct GLTypeToGLenum +{ + static GLenum value; +}; // The GL state query API types are: bool, int, uint, float, int64 template @@ -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 @@ -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 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 *MakeFramebufferMock() +{ + ::testing::NiceMock *framebufferImpl = + new ::testing::NiceMock(); + // 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 -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(indices), count); - case GL_UNSIGNED_INT: - return ComputeTypedRange(static_cast(indices), count); - case GL_UNSIGNED_SHORT: - return ComputeTypedRange(static_cast(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 - -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 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 &transformFeedbackVaryings, - GLenum transformFeedbackBufferMode, - int *registers, std::vector *linkedVaryings, - std::map *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 &getUniforms() const { return mUniforms; } - const std::vector &getUniformIndices() const { return mUniformIndex; } - const std::vector &getUniformBlocks() const { return mUniformBlocks; } - const std::vector &getTransformFeedbackLinkedVaryings() const { return mTransformFeedbackLinkedVaryings; } - const sh::Attribute *getShaderAttributes() const { return mShaderAttributes; } - const SemanticIndexArray &getSemanticIndexes() const { return mSemanticIndex; } - - std::vector &getUniforms() { return mUniforms; } - std::vector &getUniformIndices() { return mUniformIndex; } - std::vector &getUniformBlocks() { return mUniformBlocks; } - std::vector &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 mUniforms; - std::vector mUniformIndex; - std::vector mUniformBlocks; - std::vector 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 *MakeProgramMock() +{ + ::testing::NiceMock *programImpl = new ::testing::NiceMock(); + // 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 @@ -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 - #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 &getVaryings() const { return mVaryings; } - const std::vector &getUniforms() const { return mUniforms; } - const std::vector &getInterfaceBlocks() const { return mInterfaceBlocks; } - const std::vector &getActiveAttributes() const { return mActiveAttributes; } - const std::vector &getActiveOutputVariables() const { return mActiveOutputVariables; } + virtual std::string getDebugInfo() const = 0; - std::vector &getVaryings() { return mVaryings; } - std::vector &getUniforms() { return mUniforms; } - std::vector &getInterfaceBlocks() { return mInterfaceBlocks; } - std::vector &getActiveAttributes() { return mActiveAttributes; } - std::vector &getActiveOutputVariables() { return mActiveOutputVariables; } + const gl::Shader::Data &getData() const { return mData; } protected: - std::string mInfoLog; - std::string mTranslatedSource; - - std::vector mVaryings; - std::vector mUniforms; - std::vector mInterfaceBlocks; - std::vector mActiveAttributes; - std::vector 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 #include "angle_gl.h" - -#include +#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 &binding) = 0; + virtual void bindIndexedBuffer(size_t index, const OffsetBindingPointer &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 &)); + MOCK_METHOD2(bindIndexedBuffer, void(size_t, const OffsetBindingPointer &)); + + 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(getSize()), 4u) + ? 4u * static_cast(getSize()) + : std::numeric_limits::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(); + } + + 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 +#include 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 *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(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 + +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(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(device); + + ID3D11Device *d3dDevice = nullptr; + HRESULT hr = + iunknown->QueryInterface(__uuidof(ID3D11Device), reinterpret_cast(&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 @@ -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 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); + rendererCreationFunctions.push_back(CreateTypedRendererD3D); # endif # if defined(ANGLE_ENABLE_D3D9) - rendererCreationFunctions.push_back(CreateTypedRendererD3D); + rendererCreationFunctions.push_back(CreateTypedRendererD3D); # endif # else # if defined(ANGLE_ENABLE_D3D9) - rendererCreationFunctions.push_back(CreateTypedRendererD3D); + rendererCreationFunctions.push_back(CreateTypedRendererD3D); # endif # if defined(ANGLE_ENABLE_D3D11) - rendererCreationFunctions.push_back(CreateTypedRendererD3D); + rendererCreationFunctions.push_back(CreateTypedRendererD3D); # 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); + } +#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(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 &outputVariables, - unsigned int location) +const PixelShaderOutputVariable *FindOutputAtLocation( + const std::vector &outputVariables, + unsigned int location) { for (size_t variableIndex = 0; variableIndex < outputVariables.size(); ++variableIndex) { @@ -83,314 +100,102 @@ const PixelShaderOutputVariable *FindOutputAtLocation(const std::vectorisStruct()) - { - 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 &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 packedVaryings; - - std::vector &fragmentVaryings = fragmentShader->getVaryings(); - std::vector &vertexVaryings = vertexShader->getVaryings(); - for (unsigned int varyingIndex = 0; varyingIndex < fragmentVaryings.size(); varyingIndex++) + for (const PackedVaryingRegister ®isterInfo : 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 &shaderAttributes) const { - std::string varyingSemantic = getVaryingSemantic(shader->mUsesPointSize); - std::string varyingHLSL; - - const std::vector &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 &outputVariables, - bool usesFragDepth, const std::vector &outputLayout) const +std::string DynamicHLSL::generatePixelShaderForOutputSignature( + const std::string &sourceShader, + const std::vector &outputVariables, + bool usesFragDepth, + const std::vector &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(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 *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 *linkedVaryings) const -{ - const std::string &varyingSemantic = getVaryingSemantic(vertexShader->mUsesPointSize); - const std::vector &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 &transformFeedbackVaryings, - std::vector *linkedVaryings, - std::map *programOutputVars, - std::vector *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(vertexShaderGL); + const gl::Shader *fragmentShaderGL = programData.getAttachedFragmentShader(); + const ShaderD3D *fragmentShader = GetImplAs(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(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(data.caps->minAliasedPointSize) << ".0f;\n" + << "static float maxPointSize = " + << static_cast(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 &vertexVaryings = vertexShader->getVaryings(); - for (unsigned int vertVaryingIndex = 0; vertVaryingIndex < vertexVaryings.size(); vertVaryingIndex++) + for (const PackedVaryingRegister ®isterInfo : 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 &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 &fragmentVaryings = fragmentShader->getVaryings(); - for (unsigned int varyingIndex = 0; varyingIndex < fragmentVaryings.size(); varyingIndex++) + for (const PackedVaryingRegister ®isterInfo : 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 *programOutputVars) const +std::string DynamicHLSL::generateGeometryShaderPreamble(const VaryingPacking &varyingPacking) const { - const std::vector &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 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(data.caps->minAliasedPointSize) + << ".0f;\n" + "static float maxPointSize = " + << static_cast(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 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 *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 +#include #include "angle_gl.h" - -#include -#include +#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& 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 &outputVariables, - bool usesFragDepth, const std::vector &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 &transformFeedbackVaryings, - std::vector *linkedVaryings, - std::map *programOutputVars, - std::vector *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 &shaderAttributes) const; + std::string generatePixelShaderForOutputSignature( + const std::string &sourceShader, + const std::vector &outputVariables, + bool usesFragDepth, + const std::vector &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 *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 *linkedVaryings) const; - void storeBuiltinLinkedVaryings(const SemanticInfo &info, std::vector *linkedVaryings) const; - void defineOutputVariables(ShaderD3D *fragmentShader, std::map *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 + +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(mip), static_cast(layer)); + } + else + { + ASSERT(layer == 0); + return gl::ImageIndex::MakeGeneric(target, static_cast(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(GetAs(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(GetAs(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(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(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(pixels)); + return readPixelsImpl(area, format, type, outputPitch, packState, + reinterpret_cast(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(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(attachment); - const egl::Surface *surface = defaultAttachment->getSurface(); - ASSERT(surface); - const SurfaceD3D *surfaceD3D = GetImplAs(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(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(attachment); - const egl::Surface *surface = defaultAttachment->getSurface(); - ASSERT(surface); - const SurfaceD3D *surfaceD3D = GetImplAs(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 #include +#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 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 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(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(D3DCompile); mD3DDisassembleFunc = reinterpret_cast(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 &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(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(disassembly->GetBufferPointer()); + *disassemblyOut = std::string(reinterpret_cast(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 &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 ®ion) = 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(input); - GLushort *out = static_cast(output); +template +void ConvertIndexArray(const void *input, + GLenum sourceType, + void *output, + GLenum destinationType, + GLsizei count, + bool usePrimitiveRestartFixedIndex) +{ + const InputT *in = static_cast(input); + DestT *out = static_cast(output); + + if (usePrimitiveRestartFixedIndex) + { + InputT srcRestartIndex = static_cast(gl::GetPrimitiveRestartIndex(sourceType)); + DestT destRestartIndex = static_cast(gl::GetPrimitiveRestartIndex(destinationType)); for (GLsizei i = 0; i < count; i++) { - out[i] = in[i]; + out[i] = (in[i] == srcRestartIndex ? destRestartIndex : static_cast(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(in[i]); } - else if (destinationType == GL_UNSIGNED_INT) - { - const GLushort *in = static_cast(input); - GLuint *out = static_cast(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(input, sourceType, output, destinationType, count, + usePrimitiveRestartFixedIndex); + } + else if (sourceType == GL_UNSIGNED_SHORT) + { + ASSERT(destinationType == GL_UNSIGNED_INT); + ConvertIndexArray(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::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(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(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(reinterpret_cast(indices)); - - storage = GetImplAs(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(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(reinterpret_cast(indices)); + ASSERT(srcTypeInfo.bytes * static_cast(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::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(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(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 &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(rowIndex) < gl::VariableRowCount(transposedType); rowIndex++, layoutIndex++) + for (size_t rowIndex = 0; + static_cast(rowIndex) < gl::VariableRowCount(transposedType); ++rowIndex) { - gl::VertexFormat *defaultFormat = &inputLayout[layoutIndex]; + GLenum componentType = gl::VariableComponentType(transposedType); + GLuint components = static_cast(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 GetDefaultOutputLayoutFromShader(const std::vector &shaderOutputVars) +std::vector GetDefaultOutputLayoutFromShader( + const std::vector &shaderOutputVars) { std::vector defaultPixelOutput; if (!shaderOutputVars.empty()) { - defaultPixelOutput.push_back(GL_COLOR_ATTACHMENT0 + shaderOutputVars[0].outputIndex); + defaultPixelOutput.push_back(GL_COLOR_ATTACHMENT0 + + static_cast(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,49 +91,463 @@ 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 MergeVaryings(const gl::Shader &vertexShader, + const gl::Shader &fragmentShader, + const std::vector &tfVaryings) +{ + std::vector 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 +void GetUniformBlockInfo(const std::vector &fields, + const std::string &prefix, + sh::BlockLayoutEncoder *encoder, + bool inRowMajorLayout, + std::map *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 +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 +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(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(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(0), &dirty); + } + } + + return dirty; +} + +template +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(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(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(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) { - for (size_t attributeIndex = 0; attributeIndex < gl::MAX_VERTEX_ATTRIBS; attributeIndex++) + // 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) { - mInputs[attributeIndex] = inputLayout[attributeIndex]; - mSignature[attributeIndex] = signature[attributeIndex]; + 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() { 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 &outputSignature, ShaderExecutableD3D *shaderExecutable) - : mOutputSignature(outputSignature), - mShaderExecutable(shaderExecutable) +ProgramD3D::PixelExecutable::PixelExecutable(const std::vector &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(caps.maxCombinedTextureImageUnits)) + if (logicalTextureUnit >= 0 && + logicalTextureUnit < static_cast(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 (!d3dUniform->dirty) + continue; + + if (!d3dUniform->isSampler()) + continue; + + int count = d3dUniform->elementCount(); + const GLint(*v)[4] = reinterpret_cast(d3dUniform->data); - if (targetUniform->dirty) + if (d3dUniform->isReferencedByFragmentShader()) { - if (gl::IsSamplerType(targetUniform->type)) + unsigned int firstIndex = d3dUniform->psRegisterIndex; + + for (int i = 0; i < count; i++) { - int count = targetUniform->elementCount(); - GLint (*v)[4] = reinterpret_cast(targetUniform->data); + unsigned int samplerIndex = firstIndex + i; - if (targetUniform->isReferencedByFragmentShader()) + if (samplerIndex < mSamplersPS.size()) { - 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]; - } - } + 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]; - } - } - } - } - } - } -} - -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(); - - std::fill(mTextureUnitTypesCache.begin(), mTextureUnitTypesCache.end(), GL_NONE); - - for (unsigned int i = 0; i < mUsedPixelSamplerRange; ++i) - { - if (mSamplersPS[i].active) + if (d3dUniform->isReferencedByVertexShader()) { - unsigned int unit = mSamplersPS[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); - } + unsigned int samplerIndex = firstIndex + i; - return false; - } - - if (mTextureUnitTypesCache[unit] != GL_NONE) - { - if (mSamplersPS[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] = mSamplersPS[i].textureType; - } } } +} - for (unsigned int i = 0; i < mUsedVertexSamplerRange; ++i) - { - if (mSamplersVS[i].active) - { - unsigned int unit = mSamplersVS[i].logicalTextureUnit; - - if (unit >= caps.maxCombinedTextureImageUnits) - { - if (infoLog) - { - infoLog->append("Sampler uniform (%d) exceeds GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, caps.maxCombinedTextureImageUnits); - } - - return false; - } +LinkResult ProgramD3D::load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream) +{ + reset(); - if (mTextureUnitTypesCache[unit] != GL_NONE) - { - if (mSamplersVS[i].textureType != mTextureUnitTypesCache[unit]) - { - if (infoLog) - { - infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit); - } + DeviceIdentifier binaryDeviceIdentifier = {0}; + stream->readBytes(reinterpret_cast(&binaryDeviceIdentifier), + sizeof(DeviceIdentifier)); - return false; - } - } - else - { - mTextureUnitTypesCache[unit] = mSamplersVS[i].textureType; - } - } + 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)); } - return true; -} - -LinkResult ProgramD3D::load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream) -{ int compileFlags = stream->readInt(); 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(); 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(); 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 precision = stream->readInt(); - std::string name = stream->readString(); - unsigned int arraySize = stream->readInt(); - int blockIndex = stream->readInt(); - - int offset = stream->readInt(); - int arrayStride = stream->readInt(); - int matrixStride = stream->readInt(); - bool isRowMajorMatrix = stream->readBool(); - - const sh::BlockMemberInfo blockInfo(offset, arrayStride, matrixStride, isRowMajorMatrix); + const gl::LinkedUniform &linkedUniform = linkedUniforms[uniformIndex]; - 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); - - mUniforms[uniformIndex] = uniform; - } - - const unsigned int uniformIndexCount = stream->readInt(); - if (stream->error()) - { - infoLog.append("Invalid program binary."); - return LinkResult(false, gl::Error(GL_NO_ERROR)); - } + 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); - 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(); + const unsigned int blockCount = stream->readInt(); 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 dataSize = stream->readInt(); - - gl::UniformBlock *uniformBlock = new gl::UniformBlock(name, elementIndex, dataSize); - - stream->readInt(&uniformBlock->psRegisterIndex); - stream->readInt(&uniformBlock->vsRegisterIndex); - - unsigned int numMembers = stream->readInt(); - 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(); - mTransformFeedbackLinkedVaryings.resize(transformFeedbackVaryingCount); - for (unsigned int varyingIndex = 0; varyingIndex < transformFeedbackVaryingCount; varyingIndex++) + const unsigned int streamOutVaryingCount = stream->readInt(); + 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(&mVertexWorkarounds), sizeof(D3DCompilerWorkarounds)); + stream->readBytes(reinterpret_cast(&mVertexWorkarounds), + sizeof(D3DCompilerWorkarounds)); stream->readString(&mPixelHLSL); - stream->readBytes(reinterpret_cast(&mPixelWorkarounds), sizeof(D3DCompilerWorkarounds)); + stream->readBytes(reinterpret_cast(&mPixelWorkarounds), + sizeof(D3DCompilerWorkarounds)); stream->readBool(&mUsesFragDepth); stream->readBool(&mUsesPointSize); + stream->readBool(&mUsesFlatInterpolation); const size_t pixelShaderKeySize = stream->readInt(); 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(stream->data()); + stream->readString(&mGeometryShaderPreamble); + + const unsigned char *binary = reinterpret_cast(stream->data()); const unsigned int vertexShaderCount = stream->readInt(); - 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(); + 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(); } - unsigned int vertexShaderSize = stream->readInt(); + unsigned int vertexShaderSize = stream->readInt(); 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(); + const size_t pixelShaderSize = stream->readInt(); 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(); - - if (geometryShaderSize > 0) + for (unsigned int geometryExeIndex = 0; geometryExeIndex < gl::PRIMITIVE_TYPE_MAX; + ++geometryExeIndex) { + unsigned int geometryShaderSize = stream->readInt(); + 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(&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(&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); - } - - stream->writeInt(mUniformIndex.size()); - for (size_t i = 0; i < mUniformIndex.size(); ++i) - { - stream->writeString(mUniformIndex[i].name); - stream->writeInt(mUniformIndex[i].element); - stream->writeInt(mUniformIndex[i].index); + // 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(mUniformBlocks.size()); - for (size_t uniformBlockIndex = 0; uniformBlockIndex < mUniformBlocks.size(); ++uniformBlockIndex) + stream->writeInt(mD3DUniformBlocks.size()); + for (const D3DUniformBlock &uniformBlock : mD3DUniformBlocks) { - 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(&mVertexWorkarounds), sizeof(D3DCompilerWorkarounds)); + stream->writeBytes(reinterpret_cast(&mVertexWorkarounds), + sizeof(D3DCompilerWorkarounds)); stream->writeString(mPixelHLSL); - stream->writeBytes(reinterpret_cast(&mPixelWorkarounds), sizeof(D3DCompilerWorkarounds)); + stream->writeBytes(reinterpret_cast(&mPixelWorkarounds), + sizeof(D3DCompilerWorkarounds)); stream->writeInt(mUsesFragDepth); stream->writeInt(mUsesPointSize); + stream->writeInt(mUsesFlatInterpolation); const std::vector &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(&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(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::vectorgeneratePixelShaderForOutputSignature(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::vectorcompileToExecutable(*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 tempCharBuffer(tempInfoLog.getLength() + 3); - tempInfoLog.getLog(tempInfoLog.getLength(), NULL, &tempCharBuffer[0]); + tempInfoLog.getLog(static_cast(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::vectormatchesSignature(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 tempCharBuffer(tempInfoLog.getLength() + 3); - tempInfoLog.getLog(tempInfoLog.getLength(), NULL, &tempCharBuffer[0]); + tempInfoLog.getLog(static_cast(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 tempCharBuffer(tempInfoLog.getLength() + 3); + tempInfoLog.getLog(static_cast(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 defaultPixelOutput = GetDefaultOutputLayoutFromShader(getPixelShaderKey()); + std::vector 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(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(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 &transformFeedbackVaryings, - GLenum transformFeedbackBufferMode, - int *registers, std::vector *linkedVaryings, - std::map *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(vertexShader); + const ShaderD3D *fragmentShaderD3D = GetImplAs(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 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); + + varyingPacking.enableBuiltins(SHADER_VERTEX, metadata); + varyingPacking.enableBuiltins(SHADER_PIXEL, metadata); - if (*registers < 0) + if (static_cast(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*/) +{ + // 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() { - mDynamicHLSL->getInputLayoutSignature(inputLayout, signature); + mD3DUniformBlocks.clear(); + + // Assign registers and update sizes. + const ShaderD3D *vertexShaderD3D = GetImplAs(mData.getAttachedVertexShader()); + const ShaderD3D *fragmentShaderD3D = GetImplAs(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; - } - } - 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; + ASSERT(mFragmentUBOCache[registerIndex] == -1); + mFragmentUBOCache[registerIndex] = blockBinding; } } - 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); -} - -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 &vertexUniforms = vertexShader.getUniforms(); - const std::vector &fragmentUniforms = fragmentShader.getUniforms(); - - // Check that uniforms defined in the vertex and fragment shaders are identical - typedef std::map UniformMap; - UniformMap linkedUniforms; + D3DUniformMap uniformMap; + const gl::Shader *vertexShader = mData.getAttachedVertexShader(); + for (const sh::Uniform &vertexUniform : vertexShader->getUniforms()) - 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 (!glUniform.isInDefaultBlock()) + continue; - if (uniform.staticUse) - { - defineUniformBase(fragmentShaderD3D, uniform, fragmentShaderD3D->getUniformRegister(uniform.name)); - } - } - - 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(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(sh::HLSLBlockEncoder::getBlockRegisterElement(blockInfo)); + unsigned int reg = + static_cast(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 -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 -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); - - int elementCount = targetUniform->elementCount(); + D3DUniform *targetUniform = getD3DUniformFromLocation(location); - 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(countIn)); if (targetUniform->type == targetUniformType) { - T *target = reinterpret_cast(targetUniform->data) + mUniformIndex[location].element * 4; + T *target = reinterpret_cast(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(targetUniform->data) + mUniformIndex[location].element * 4; + GLint *boolParams = reinterpret_cast(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(0)) ? GL_FALSE : GL_TRUE, &targetUniform->dirty); + SetIfDirty(dest + c, (source[c] == static_cast(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(targetUniform->data) + mUniformIndex[location].element * 4; + GLint *target = reinterpret_cast(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(v) + (i * components); + GLint *dest = target + (i * 4); + const GLint *source = reinterpret_cast(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 -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(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(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(0), &dirty); - } - } - - return dirty; -} - -template -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(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(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(0), &dirty); - } - } - - return dirty; + else + UNREACHABLE(); } template -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(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(target, value, 4, rows, rows, cols) || targetUniform->dirty; + targetUniform->dirty = TransposeMatrix(target, value, 4, rows, rows, cols) || + targetUniform->dirty; } else { - targetUniform->dirty = expandMatrix(target, value, 4, rows, cols, rows) || targetUniform->dirty; + targetUniform->dirty = + ExpandMatrix(target, value, 4, rows, cols, rows) || targetUniform->dirty; } target += targetMatrixStride; value += cols * rows; } } -template -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(0) : static_cast(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(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(intParams[i]); - } - } - break; - - case GL_UNSIGNED_INT: - { - GLuint *uintParams = (GLuint*)targetUniform->data + mUniformIndex[location].element * 4; + encoder = &hlslEncoder; + } - for (unsigned int i = 0; i < size; i++) - { - params[i] = static_cast(uintParams[i]); - } - } - break; + GetUniformBlockInfo(interfaceBlock.fields, interfaceBlock.fieldPrefix(), encoder, + interfaceBlock.isRowMajorLayout, &mBlockInfo); - default: UNREACHABLE(); - } - } + return encoder->getBlockSize(); } -template -void ProgramD3D::defineUniformBlockMembers(const std::vector &fields, const std::string &prefix, int blockIndex, - sh::BlockLayoutEncoder *encoder, std::vector *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()) + if (d3dUniform->isSampler()) { - 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 - { - 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 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 &outSamplers, - GLuint *outUsedRange) +// static +void ProgramD3D::AssignSamplers(unsigned int startSamplerIndex, + GLenum samplerType, + unsigned int samplerCount, + std::vector &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( + const std::vector &unsortedAttributes, + int sortedSemanticIndicesOut[gl::MAX_VERTEX_ATTRIBS], + const rx::TranslatedAttribute *sortedAttributesOut[gl::MAX_VERTEX_ATTRIBS]) const +{ + for (size_t attribIndex = 0; attribIndex < unsortedAttributes.size(); ++attribIndex) + { + int oldIndex = mAttributesByLayout[attribIndex]; + sortedSemanticIndicesOut[attribIndex] = mSemanticIndexes[oldIndex]; + sortedAttributesOut[attribIndex] = &unsortedAttributes[oldIndex]; + } } -void ProgramD3D::sortAttributesByLayout(rx::TranslatedAttribute attributes[gl::MAX_VERTEX_ATTRIBS], - int sortedSemanticIndices[gl::MAX_VERTEX_ATTRIBS]) const +void ProgramD3D::updateCachedInputLayout(const gl::State &state) { - rx::TranslatedAttribute oldTranslatedAttributes[gl::MAX_VERTEX_ATTRIBS]; + mCachedInputLayout.clear(); + const auto &vertexAttributes = state.getVertexArray()->getVertexAttributes(); - for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) + for (unsigned int attributeIndex : angle::IterateBitSet(mData.getActiveAttribLocationsMask())) { - oldTranslatedAttributes[i] = attributes[i]; + int semanticIndex = mSemanticIndexes[attributeIndex]; + + if (semanticIndex != -1) + { + if (mCachedInputLayout.size() < static_cast(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(tfVaryingNames.size()); + ++outputSlot) { - int oldIndex = mAttributesByLayout[i]; - sortedSemanticIndices[i] = mSemanticIndex[oldIndex]; - attributes[i] = oldTranslatedAttributes[oldIndex]; + 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 ®isterInfo : 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()) + { + *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 +#include + #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 -#include - -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 &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 &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 &transformFeedbackVaryings, - GLenum transformFeedbackBufferMode, - int *registers, std::vector *linkedVaryings, - std::map *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 &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 &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 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 &outputSignature, ShaderExecutableD3D *shaderExecutable); + PixelExecutable(const std::vector &outputSignature, + ShaderExecutableD3D *shaderExecutable); ~PixelExecutable(); - bool matchesSignature(const std::vector &signature) const { return mOutputSignature == signature; } + bool matchesSignature(const std::vector &signature) const + { + return mOutputSignature == signature; + } const std::vector &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 &outSamplers, GLuint *outUsedRange); + typedef std::map 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 &outSamplers, + GLuint *outUsedRange); template - void setUniform(GLint location, GLsizei count, const T* v, GLenum targetUniformType); + void setUniform(GLint location, GLsizei count, const T *v, GLenum targetUniformType); template - 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 - void getUniformv(GLint location, T *params, GLenum uniformType); + LinkResult compileProgramExecutables(const gl::Data &data, gl::InfoLog &infoLog); - template - void defineUniformBlockMembers(const std::vector &fields, const std::string &prefix, int blockIndex, - sh::BlockLayoutEncoder *encoder, std::vector *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 mVertexExecutables; std::vector mPixelExecutables; - ShaderExecutableD3D *mGeometryExecutable; + std::vector mGeometryExecutables; std::string mVertexHLSL; D3DCompilerWorkarounds mVertexWorkarounds; @@ -210,35 +365,46 @@ class ProgramD3D : public ProgramImpl bool mUsesFragDepth; std::vector 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 mSamplersPS; std::vector mSamplersVS; GLuint mUsedVertexSamplerRange; GLuint mUsedPixelSamplerRange; bool mDirtySamplerMapping; - // Cache for validateSamplers - std::vector mTextureUnitTypesCache; - // Cache for getPixelExecutableForFramebuffer std::vector mPixelShaderOutputFormatCache; - int mShaderVersion; - - int mAttributesByLayout[gl::MAX_VERTEX_ATTRIBS]; + SemanticIndexArray mSemanticIndexes; + SemanticIndexArray mAttributesByLayout; unsigned int mSerial; + std::vector mVertexUBOCache; + std::vector mFragmentUBOCache; + VertexExecutable::Signature mCachedVertexSignature; + gl::InputLayout mCachedInputLayout; + + std::vector mStreamOutVaryings; + std::vector mD3DUniforms; + std::vector mD3DUniformBlocks; + + std::map mBlockInfo; + std::map 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(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(width), static_cast(height), + creationFormat, static_cast(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(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(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(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(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(indexInfo.indexRange.start), + static_cast(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(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(data.state->getProgram()); - size_t samplerRange = program->getUsedSamplerRange(type); + unsigned int samplerRange = static_cast(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(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(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(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 &binding = transformFeedback->getIndexedBuffer(i); + if (binding.get() != nullptr) { - BufferD3D *bufferD3D = GetImplAs(buffer); + BufferD3D *bufferD3D = GetImplAs(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::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 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 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 &vertexUniformBuffers, + const std::vector &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 &uniformArray) = 0; + virtual gl::Error applyUniforms(const ProgramD3D &programD3D, + GLenum drawMode, + const std::vector &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 &transformFeedbackVaryings, - bool separatedOutputBuffers, ShaderExecutableD3D **outExecutable) = 0; - virtual gl::Error compileToExecutable(gl::InfoLog &infoLog, const std::string &shaderHLSL, ShaderType type, - const std::vector &transformFeedbackVaryings, - bool separatedOutputBuffers, const D3DCompilerWorkarounds &workarounds, + virtual gl::Error loadExecutable(const void *function, + size_t length, + ShaderType type, + const std::vector &streamOutVaryings, + bool separatedOutputBuffers, + ShaderExecutableD3D **outExecutable) = 0; + virtual gl::Error compileToExecutable(gl::InfoLog &infoLog, + const std::string &shaderHLSL, + ShaderType type, + const std::vector &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 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 FramebufferTextureSerialArray; + typedef std::array 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 -void FilterInactiveVariables(std::vector *variableList) -{ - ASSERT(variableList); - - for (size_t varIndex = 0; varIndex < variableList->size();) - { - if (!(*variableList)[varIndex].staticUse) - { - variableList->erase(variableList->begin() + varIndex); - } - else - { - varIndex++; - } - } -} - -template -const std::vector *GetShaderVariables(const std::vector *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(impl); -} - -const ShaderD3D *ShaderD3D::makeShaderD3D(const ShaderImpl *impl) -{ - ASSERT(HAS_DYNAMIC_TYPE(const ShaderD3D*, impl)); - return static_cast(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 *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(-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(-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(-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(-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 @@ -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 mUniformRegisterMap; std::map 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 @@ -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(0), window); + return new SurfaceD3D(renderer, display, config, width, height, fixedSize, orientation, + directComposition, static_cast(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(shareHandle)) + mShareHandle(reinterpret_cast(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(GetProp(hwnd, kSurfaceProperty)); - if(surf) - { - surf->checkForOutOfDateSwapChain(); - } - } - WNDPROC prevWndFunc = reinterpret_cast(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(SurfaceWindowProc)); - if(oldWndProc == 0 && GetLastError() != ERROR_SUCCESS) - { - mWindowSubclassed = false; - return; - } - - SetProp(window, kSurfaceProperty, reinterpret_cast(this)); - SetProp(window, kParentWndProc, reinterpret_cast(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(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(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(pixels); - gl::Error error = mRenderer->fastCopyBufferToTexture(unpack, offset, destRenderTarget, sizedInternalFormat, type, destArea); + gl::Error error = mRenderer->fastCopyBufferToTexture(unpack, static_cast(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(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(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(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(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(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(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(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(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(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(image); + + // Set the properties of the base mip level from the EGL image + GLenum internalformat = image->getInternalFormat(); + gl::Extents size(static_cast(image->getWidth()), static_cast(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(level)); - redefineImage(index.layerIndex, level, sizedInternalFormat, size); + redefineImage(index.layerIndex, static_cast(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(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(faceIndex), static_cast(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(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(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(gl::CubeMapTextureTargetToLayerIndex(target)); GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, GL_UNSIGNED_BYTE); + GLint level = static_cast(imageLevel); + gl::Extents size(sourceArea.width, sourceArea.height, 1); - redefineImage(faceIndex, level, sizedInternalFormat, size); + redefineImage(static_cast(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(gl::CubeMapTextureTargetToLayerIndex(target)); + GLint level = static_cast(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(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(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(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(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(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(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(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(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(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(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(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(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(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 &binding) +{ +} + +void TransformFeedbackD3D::bindIndexedBuffer(size_t index, const OffsetBindingPointer &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 &binding) override; + void bindIndexedBuffer(size_t index, const OffsetBindingPointer &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(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 &packedVaryings, + const std::vector &transformFeedbackVaryings) +{ + std::set 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(mRegisterList.size()); ++semanticIndex) + { + mRegisterList[semanticIndex].semanticIndex = semanticIndex; + } + + return true; +} + +unsigned int VaryingPacking::getRegisterCount() const +{ + unsigned int count = 0; + + for (const Register ® : 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 &packedVaryings, + const std::vector &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 &getRegisterList() const { return mRegisterList; } + unsigned int getMaxSemanticIndex() const + { + return static_cast(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 mRegisterMap; + std::vector mRegisterList; + + std::vector 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 ¤tValue, - 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 ¤tValue) const + GLenum currentValueType) const { gl::Buffer *buffer = attrib.buffer.get(); BufferD3D *storage = buffer ? GetImplAs(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(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(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(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(attrib.offset) % ComputeVertexAttributeStride(attrib)); + size_t offset = (static_cast(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 ¤tValue, - 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 #include +#include #include 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 ¤tValue, - 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 ¤tValue, - 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 ¤tValue) 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 ¤tValue, - 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 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(std::numeric_limits::max()); } - GLsizei stride = ComputeVertexAttributeStride(attrib); - return (size - attrib.offset % stride + (stride - ComputeVertexAttributeTypeSize(attrib))) / stride; + GLsizei stride = static_cast(ComputeVertexAttributeStride(attrib)); + return (size - attrib.offset % stride + + (stride - static_cast(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::quiet_NaN(); + data.FloatValues[1] = std::numeric_limits::quiet_NaN(); + data.FloatValues[2] = std::numeric_limits::quiet_NaN(); + data.FloatValues[3] = std::numeric_limits::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::quiet_NaN(); - mCurrentValue[i].FloatValues[1] = std::numeric_limits::quiet_NaN(); - mCurrentValue[i].FloatValues[2] = std::numeric_limits::quiet_NaN(); - mCurrentValue[i].FloatValues[3] = std::numeric_limits::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 &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(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(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 ¤tValue : 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 *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 &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(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(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(buffer); - bufferImpl->promoteStaticUsage(count * ComputeVertexAttributeTypeSize(curAttrib)); - } + gl::Error error = storeCurrentValue( + state.getVertexAttribCurrentValue(static_cast(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 ¤tValue) 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(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(buffer); + size_t typeSize = ComputeVertexAttributeTypeSize(*activeAttrib->attribute); + bufferD3D->promoteStaticUsage(count * static_cast(typeSize)); } } + + return gl::Error(GL_NO_ERROR); } -gl::Error VertexDataManager::reserveSpaceForAttrib(const gl::VertexAttribute &attrib, - const gl::VertexAttribCurrentValueData ¤tValue, +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(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(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(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(bufferImpl->getSize())) >= + static_cast(totalCount)); - gl::Error error = mStreamingBuffer->reserveVertexSpace(attrib, totalCount, instances); + gl::Error error = mStreamingBuffer->reserveVertexSpace( + attrib, static_cast(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 ¤tValue, - 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(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(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(ComputeVertexAttributeStride(attrib)); + translated->offset = static_cast(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(attrib.offset); + } + else + { + sourceData = static_cast(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(storage->getSize())); + int startIndex = static_cast(attrib.offset) / + static_cast(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(attrib.offset) / + static_cast(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(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 ¤tValue, +gl::Error VertexDataManager::storeCurrentValue(const gl::VertexAttribCurrentValueData ¤tValue, 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(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(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 *translatedAttribs, + GLsizei instances); private: - gl::Error reserveSpaceForAttrib(const gl::VertexAttribute &attrib, - const gl::VertexAttribCurrentValueData ¤tValue, + 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 ¤tValue) const; - - gl::Error storeAttribute(const gl::VertexAttribute &attrib, - const gl::VertexAttribCurrentValueData ¤tValue, - TranslatedAttribute *translated, + gl::Error storeAttribute(TranslatedAttribute *translated, GLint start, GLsizei count, GLsizei instances); - gl::Error storeCurrentValue(const gl::VertexAttribute &attrib, - const gl::VertexAttribCurrentValueData ¤tValue, + gl::Error storeCurrentValue(const gl::VertexAttribCurrentValueData ¤tValue, TranslatedAttribute *translated, - gl::VertexAttribCurrentValueData *cachedValue, - size_t *cachedOffset, - StreamingVertexBufferInterface *buffer); + CurrentValueState *cachedState); void hintUnmapAllResources(const std::vector &vertexAttributes); BufferFactoryD3D *const mFactory; StreamingVertexBufferInterface *mStreamingBuffer; + std::vector 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 mActiveEnabledAttributes; + std::vector 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 +#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(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(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(size.width); + viewport.Height = static_cast(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(destSize.width); + viewport.Height = static_cast(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(destSize.width); + viewport.Height = static_cast(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(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(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(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(gl::clamp(sourceArea.x + floor(xPerc * (sourceArea.width - 1) + 0.5f), 0, sourceSize.width - 1)); unsigned int writeColumn = x; void *sourcePixel = reinterpret_cast(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 @@ -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 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 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 mBlitShaderMap; + std::map 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 mQuad2DVS; + d3d11::LazyShader mDepthPS; + + d3d11::LazyInputLayout mQuad3DIL; + d3d11::LazyShader mQuad3DVS; + d3d11::LazyShader 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 + #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 +GLuint ReadIndexValueFromIndices(const uint8_t *data, size_t index) +{ + return reinterpret_cast(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 ¶ms); + gl::Error packPixels(const gl::FramebufferAttachment &readAttachment, + const PackPixelsParams ¶ms); private: gl::Error flushQueuedPackCommand(); - ID3D11Texture2D *mStagingTexture; - DXGI_FORMAT mTextureFormat; - gl::Extents mTextureSize; + TextureHelper11 mStagingTexture; MemoryBuffer mMemoryBuffer; - PackPixelsParams *mQueuedPackCommand; + std::unique_ptr 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(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(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(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(bufferStorage)->getNativeStorage(); +} + +ID3D11Buffer *Buffer11::getEmulatedIndexedBuffer(SourceIndexData *indexInfo, + const TranslatedAttribute *attribute) +{ + markBufferUsage(); + + assert(indexInfo != nullptr); + assert(attribute != nullptr); - return static_cast(bufferStorage)->getNativeStorage(); + BufferStorage *bufferStorage = getBufferStorage(BUFFER_USAGE_EMULATED_INDEXED_VERTEX); + if (!bufferStorage) + { + // Storage out-of-memory + return nullptr; + } + + EmulatedIndexedStorage *emulatedStorage = GetAs(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(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(storage)->getNativeStorage(); + ID3D11Buffer *buffer = GetAs(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(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 ¶ms) +gl::Error Buffer11::packPixels(const gl::FramebufferAttachment &readAttachment, + const PackPixelsParams ¶ms) { - 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)) + { + 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(stagingStorage); + return GetAs(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); + return GetAs(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(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(sourceOffset); + srcBox.right = static_cast(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(source)->getNativeStorage(); + ID3D11Buffer *sourceBuffer = GetAs(source)->getNativeStorage(); - context->CopySubresourceRegion(mNativeStorage, 0, destOffset, 0, 0, sourceBuffer, 0, &srcBox); + context->CopySubresourceRegion(mNativeStorage, 0, static_cast(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(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(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(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(bufferDesc->ByteWidth, + static_cast(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(mappedResource.pData) + offset; + if (FAILED(result)) + { + return nullptr; + } + return static_cast(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((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(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; + + switch (mIndexInfo.srcIndexType) + { + case GL_UNSIGNED_INT: + readIndexValue = ReadIndexValueFromIndices; + break; + case GL_UNSIGNED_SHORT: + readIndexValue = ReadIndexValueFromIndices; + break; + case GL_UNSIGNED_BYTE: + readIndexValue = ReadIndexValueFromIndices; + 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 ¶ms) +gl::Error Buffer11::PackStorage::packPixels(const gl::FramebufferAttachment &readAttachment, + const PackPixelsParams ¶ms) { 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(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 + #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 ¶ms); + gl::Error packPixels(const gl::FramebufferAttachment &readAttachment, + const PackPixelsParams ¶ms); + 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 mBufferStorages; + std::vector 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 ConstantBufferCache; + ConstantBufferCache mConstantBufferRangeStoragesCache; + size_t mConstantBufferStorageAdditionalSize; + unsigned int mMaxConstantBufferLruCount; typedef std::pair BufferSRVPair; std::map 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(vertices + 3, right, top, depthClear, color); } -template -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), mClearDepthStencilStates(StructLessThan), - mVertexBuffer(NULL), mRasterizerState(NULL), mSupportsClearView(false) + : mRenderer(renderer), + mClearBlendStates(StructLessThan), + mFloatClearShader(nullptr), + mUintClearShader(nullptr), + mIntClearShader(nullptr), + mClearDepthStencilStates(StructLessThan), + 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 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); - shader = &mFloatClearShader; + shader = mFloatClearShader; break; case GL_UNSIGNED_INT: ApplyVertices(framebufferSize, scissorPtr, clearParams.colorUIClearValue, clearParams.depthClearValue, mappedResource.pData); vertexStride = sizeof(d3d11::PositionDepthColorVertex); - shader = &mUintClearShader; + shader = mUintClearShader; break; case GL_INT: ApplyVertices(framebufferSize, scissorPtr, clearParams.colorIClearValue, clearParams.depthClearValue, mappedResource.pData); vertexStride = sizeof(d3d11::PositionDepthColorVertex); - 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(framebufferSize.width); + viewport.Height = static_cast(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(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& 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& } 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 &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 vertexShader; + d3d11::LazyShader pixelShader; }; template 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 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 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(context); - ASSERT(mUserDefinedAnnotation != nullptr); + mUserDefinedAnnotation = d3d11::DynamicCastComObject(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(¤tCounter); 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 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 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(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(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(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(colorAttachmentID))) + { + error = mData.getColorAttachment(static_cast(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(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(packBuffer); + PackPixelsParams packParams(area, format, type, static_cast(outputPitch), pack, + reinterpret_cast(pixels)); + + return packBufferStorage->packPixels(*readAttachment, packParams); + } + + return mRenderer->readFromAttachment(*readAttachment, area, format, type, + static_cast(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(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(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(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(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 ®ion) { - TextureStorage11 *storage11 = TextureStorage11::makeTextureStorage11(storage); + TextureStorage11 *storage11 = GetAs(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(mappedImage.pData) + (area.y * mappedImage.RowPitch + area.x * outputPixelSize + area.z * mappedImage.DepthPitch)); loadFunction(area.width, area.height, area.depth, - reinterpret_cast(input), inputRowPitch, inputDepthPitch, - offsetMappedData, mappedImage.RowPitch, mappedImage.DepthPitch); + reinterpret_cast(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(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(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(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(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(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(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 initialData; - std::vector< std::vector > textureData; - d3d11::GenerateInitialTextureData(mInternalFormat, mFeatureLevel, width, height, mDepth, + std::vector> 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 initialData; - std::vector< std::vector > textureData; - d3d11::GenerateInitialTextureData(mInternalFormat, mFeatureLevel, width, height, 1, + std::vector> 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 ®ion); - 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(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 &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 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(index); } } + + return Optional::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(attribType); + packedAttrib.semanticIndex = static_cast(semanticIndex); + packedAttrib.vertexFormatType = static_cast(vertexFormatType); + packedAttrib.divisor = static_cast(divisor); + + ASSERT(static_cast(packedAttrib.attribType) == attribType); + ASSERT(static_cast(packedAttrib.semanticIndex) == semanticIndex); + ASSERT(static_cast(packedAttrib.vertexFormatType) == vertexFormatType); + ASSERT(static_cast(packedAttrib.divisor) == divisor); + + static_assert(sizeof(uint32_t) == sizeof(PackedAttribute), "PackedAttributes must be 32-bits exactly."); + + attributeData[numAttributes++] = gl::bitCast(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(-1); mCurrentVertexOffsets[i] = static_cast(-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 &unsortedAttributes, + GLenum mode, + gl::Program *program, + TranslatedIndexData *indexInfo, + GLsizei numIndicesPerInstance) { + ASSERT(mDevice && mDeviceContext); + ProgramD3D *programD3D = GetImplAs(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 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(attrib.vertexBuffer); + Buffer11 *bufferStorage = attrib.storage ? GetAs(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(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(i)); - maxDiff = std::max(maxDiff, static_cast(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(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(minDiff), static_cast(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 &shaderAttributes = program->getAttributes(); + PackedAttributeLayout layout; + + ProgramD3D *programD3D = GetImplAs(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(program); + + bool programUsesInstancedPointSprites = + programD3D->usesPointSize() && programD3D->usesInstancedPointSpriteEmulation(); + + unsigned int inputElementCount = 0; + std::array 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(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(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 #include -#include + +#include +#include + +#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; +using SortedIndexArray = std::array; 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 &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(&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(&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 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 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 +#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 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(sourceBuffer.getImplementation()); ID3D11ShaderResourceView *bufferSRV = bufferStorage11->getSRV(srvFormat); ASSERT(bufferSRV != NULL); - ID3D11RenderTargetView *textureRTV = RenderTarget11::makeRenderTarget11(destRenderTarget)->getRenderTargetView(); + ID3D11RenderTargetView *textureRTV = GetAs(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(destSize.width); + viewport.Height = static_cast(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..c0bed2b43a 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Query11.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Query11.cpp @@ -18,6 +18,11 @@ typedef struct D3D11_QUERY_DATA_SO_STATISTICS { UINT64 NumPrimitivesWritten; UINT64 PrimitivesStorageNeeded; } D3D11_QUERY_DATA_SO_STATISTICS; + +typedef struct D3D11_QUERY_DATA_TIMESTAMP_DISJOINT { + UINT64 Frequency; + BOOL Disjoint; +} D3D11_QUERY_DATA_TIMESTAMP_DISJOINT; #endif namespace rx @@ -28,38 +33,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 +115,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 +gl::Error Query11::getResultBase(T *params) { while (!mQueryFinished) { @@ -84,12 +142,32 @@ gl::Error Query11::getResult(GLuint *params) } ASSERT(mQueryFinished); - *params = mResult; + *params = static_cast(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 +175,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 +219,74 @@ gl::Error Query11::testQuery() if (result == S_OK) { mQueryFinished = true; - mResult = static_cast(soStats.NumPrimitivesWritten); + mResult = static_cast(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::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 + 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 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(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(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(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 +#include +#if !defined(ANGLE_MINGW32_COMPAT) && WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP +#include +#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 -#include +// 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(-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(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(rx::roundUp(size, static_cast(256)) / 16); + + // 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 -static bool ImageIndexConflictsWithSRV(const gl::ImageIndex *index, D3D11_SHADER_RESOURCE_VIEW_DESC desc) +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(i); + } + dest[count] = 0; +} - return type == GL_TEXTURE_2D && RangeUI(mipMin, mipMax).intersects(RangeUI(desc.Texture2D.MostDetailedMip, maxSrvMip)); - } +template +void CopyLineLoopIndices(const GLvoid *indices, GLuint *dest, size_t count) +{ + const T *srcPtr = static_cast(indices); + for (size_t i = 0; i < count; ++i) + { + dest[i] = static_cast(srcPtr[i]); + } + dest[count] = static_cast(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(i) + 1; + destPtr[i * 3 + 2] = static_cast(i) + 2; + } +} - unsigned maxSlice = desc.Texture2DArray.FirstArraySlice + desc.Texture2DArray.ArraySize; +template +void CopyLineLoopIndicesWithRestart(const GLvoid *indices, + size_t count, + GLenum indexType, + std::vector *bufferOut) +{ + GLuint restartIndex = gl::GetPrimitiveRestartIndex(indexType); + GLuint d3dRestartIndex = static_cast(d3d11::GetPrimitiveRestartIndex()); + const T *srcPtr = static_cast(indices); + Optional currentLoopStart; - // 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; - } + bufferOut->clear(); - case D3D11_SRV_DIMENSION_TEXTURECUBE: - { - unsigned maxSrvMip = desc.TextureCube.MipLevels + desc.TextureCube.MostDetailedMip; - maxSrvMip = (desc.TextureCube.MipLevels == -1) ? INT_MAX : maxSrvMip; + for (size_t indexIdx = 0; indexIdx < count; ++indexIdx) + { + GLuint value = static_cast(srcPtr[indexIdx]); - return gl::IsCubeMapTextureTarget(type) && - desc.TextureCube.MostDetailedMip <= mipLevel && mipLevel < maxSrvMip; + if (value == restartIndex) + { + 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()); + } +} + +void GetLineLoopIndices(const GLvoid *indices, + GLenum indexType, + GLuint count, + bool usePrimitiveRestartFixedIndex, + std::vector *bufferOut) +{ + if (indexType != GL_NONE && usePrimitiveRestartFixedIndex) + { + switch (indexType) + { + case GL_UNSIGNED_BYTE: + CopyLineLoopIndicesWithRestart(indices, count, indexType, bufferOut); + break; + case GL_UNSIGNED_SHORT: + CopyLineLoopIndicesWithRestart(indices, count, indexType, bufferOut); + break; + case GL_UNSIGNED_INT: + CopyLineLoopIndicesWithRestart(indices, count, indexType, bufferOut); + break; + default: + UNREACHABLE(); + break; + } + return; + } + + // For non-primitive-restart draws, the index count is static. + bufferOut->resize(static_cast(count) + 1); + + switch (indexType) + { + // Non-indexed draw + case GL_NONE: + SetLineLoopIndices(&(*bufferOut)[0], count); + break; + case GL_UNSIGNED_BYTE: + CopyLineLoopIndices(indices, &(*bufferOut)[0], count); + break; + case GL_UNSIGNED_SHORT: + CopyLineLoopIndices(indices, &(*bufferOut)[0], count); + break; + case GL_UNSIGNED_INT: + CopyLineLoopIndices(indices, &(*bufferOut)[0], count); + break; + default: + UNREACHABLE(); + break; + } } -// Does *not* increment the resource ref count!! -ID3D11Resource *GetViewResource(ID3D11View *view) +template +void CopyTriangleFanIndices(const GLvoid *indices, GLuint *destPtr, size_t numTris) { - ID3D11Resource *resource = NULL; - ASSERT(view); - view->GetResource(&resource); - resource->Release(); - return resource; + const T *srcPtr = static_cast(indices); + + for (size_t i = 0; i < numTris; i++) + { + destPtr[i * 3 + 0] = static_cast(srcPtr[0]); + destPtr[i * 3 + 1] = static_cast(srcPtr[i + 1]); + destPtr[i * 3 + 2] = static_cast(srcPtr[i + 2]); + } } -void CalculateConstantBufferParams(GLintptr offset, GLsizeiptr size, UINT *outFirstConstant, UINT *outNumConstants) +template +void CopyTriangleFanIndicesWithRestart(const GLvoid *indices, + GLuint indexCount, + GLenum indexType, + std::vector *bufferOut) { - // The offset must be aligned to 256 bytes (should have been enforced by glBindBufferRange). - ASSERT(offset % 256 == 0); + GLuint restartIndex = gl::GetPrimitiveRestartIndex(indexType); + GLuint d3dRestartIndex = gl::GetPrimitiveRestartIndex(GL_UNSIGNED_INT); + const T *srcPtr = static_cast(indices); + Optional vertexA; + Optional vertexB; - // firstConstant and numConstants are expressed in constants of 16-bytes. Furthermore they must be a multiple of 16 constants. - *outFirstConstant = offset / 16; + bufferOut->clear(); - // 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(256)) / 16; + for (size_t indexIdx = 0; indexIdx < indexCount; ++indexIdx) + { + GLuint value = static_cast(srcPtr[indexIdx]); - // 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 + 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 *bufferOut) +{ + if (indexType != GL_NONE && usePrimitiveRestartFixedIndex) + { + switch (indexType) + { + case GL_UNSIGNED_BYTE: + CopyTriangleFanIndicesWithRestart(indices, count, indexType, bufferOut); + break; + case GL_UNSIGNED_SHORT: + CopyTriangleFanIndicesWithRestart(indices, count, indexType, bufferOut); + break; + case GL_UNSIGNED_INT: + CopyTriangleFanIndicesWithRestart(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(indices, &(*bufferOut)[0], numTris); + break; + case GL_UNSIGNED_SHORT: + CopyTriangleFanIndices(indices, &(*bufferOut)[0], numTris); + break; + case GL_UNSIGNED_INT: + CopyTriangleFanIndices(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(-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(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(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(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(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(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(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(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(mDevice); #endif +#endif // !ANGLE_MINGW32_COMPAT + + initializeDevice(); - memset(mDescription, 0, sizeof(mDescription)); - wcstombs(mDescription, mAdapterDescription.Description, sizeof(mDescription) - 1); + 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."); + } + + // create the D3D11 device + ASSERT(mDevice == nullptr); + D3D11CreateDevice = reinterpret_cast( + 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(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(mAvailableFeatureLevels.size()), D3D11_SDK_VERSION, + &mDevice, &(mRenderer11DeviceCaps.featureLevel), &mDeviceContext); - if (SUCCEEDED(result)) + // Cleanup done by destructor + if (!mDevice || FAILED(result)) + { + ANGLE_HISTOGRAM_SPARSE_SLOWLY("GPU.ANGLE.D3D11CreateDeviceError", + static_cast(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(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(mDxgiAdapter); + mRenderer11DeviceCaps.supportsDXGI1_2 = (dxgiAdapter2 != nullptr); + SafeRelease(dxgiAdapter2); +#endif } egl::ConfigSet Renderer11::generateConfigs() const { - static const GLenum colorBufferFormats[] = + std::vector 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) + { + continue; + } + + for (GLenum depthStencilBufferInternalFormat : depthStencilBufferFormats) { - for (size_t depthStencilIndex = 0; depthStencilIndex < ArraySize(depthStencilBufferFormats); depthStencilIndex++) + 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(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(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(); @@ -748,12 +1110,34 @@ gl::Error Renderer11::finish() } while (result == S_FALSE); - return gl::Error(GL_NO_ERROR); + return gl::Error(GL_NO_ERROR); +} + +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); + } } -SwapChainD3D *Renderer11::createSwapChain(NativeWindow nativeWindow, HANDLE shareHandle, GLenum backBufferFormat, GLenum depthBufferFormat) +void *Renderer11::getD3DDevice() { - return new SwapChain11(this, nativeWindow, shareHandle, backBufferFormat, depthBufferFormat); + return reinterpret_cast(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(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(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(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(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(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(index) < getRendererCaps().maxTextureImageUnits) || (type == gl::SAMPLER_VERTEX && static_cast(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 &vertexUniformBuffers, + const std::vector &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 &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(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(uniformBufferIndex), + 1, &constantBuffer, &firstConstant, &numConstants); } else #endif { - ASSERT(uniformBufferOffset == 0); - mDeviceContext->VSSetConstantBuffers(getReservedVertexUniformBuffers() + uniformBufferIndex, - 1, &constantBuffer); + mDeviceContext->VSSetConstantBuffers( + getReservedVertexUniformBuffers() + + static_cast(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 &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(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(uniformBufferIndex), + 1, &constantBuffer, &firstConstant, &numConstants); } else #endif { - ASSERT(uniformBufferOffset == 0); - mDeviceContext->PSSetConstantBuffers(getReservedFragmentUniformBuffers() + uniformBufferIndex, - 1, &constantBuffer); + mDeviceContext->PSSetConstantBuffers( + getReservedFragmentUniformBuffers() + + static_cast(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; - - return gl::Error(GL_NO_ERROR); -} - -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); + // Set the present path state + const bool presentPathFastActive = + UsePresentPathFast(this, framebufferObject->getFirstColorbuffer()); + mStateManager.updatePresentPath(presentPathFastActive, + framebufferObject->getFirstColorbuffer()); - 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 viewport state + mStateManager.setViewport(data.caps, data.state->getViewport(), data.state->getNearPlane(), + data.state->getFarPlane()); - mForceSetBlendState = false; + // Setting scissor state + mStateManager.setScissorRectangle(data.state->getScissor(), data.state->isScissorTestEnabled()); - return gl::Error(GL_NO_ERROR); -} + // 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); -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(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(caps.maxViewportWidth); - int dxMaxViewportBoundsY = static_cast(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(dxViewportTopLeftX); - dxViewport.TopLeftY = static_cast(dxViewportTopLeftY); - dxViewport.Width = static_cast(dxViewportWidth); - dxViewport.Height = static_cast(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((actualViewport.width - dxViewportWidth) + 2 * (actualViewport.x - dxViewportTopLeftX)) / dxViewport.Width; - mVertexConstants.viewAdjust[1] = static_cast((actualViewport.height - dxViewportHeight) + 2 * (actualViewport.y - dxViewportTopLeftY)) / dxViewport.Height; - mVertexConstants.viewAdjust[2] = static_cast(actualViewport.width) / dxViewport.Width; - mVertexConstants.viewAdjust[3] = static_cast(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 ¤tSRVs = (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(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(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(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(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(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(framebufferRTVs[rtIndex]); - } - mAppliedDSV = reinterpret_cast(framebufferDSV); - mRenderTargetDescInitialized = true; - mDepthStencilInitialized = true; - } - - const Framebuffer11 *framebuffer11 = GetImplAs(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(indexInfo->storage); buffer = storage->getBuffer(BUFFER_USAGE_INDEX); } else { - IndexBuffer11* indexBuffer = IndexBuffer11::makeIndexBuffer11(indexInfo->indexBuffer); + IndexBuffer11* indexBuffer = GetAs(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 &binding = transformFeedback->getIndexedBuffer(i); + ID3D11Buffer *d3dBuffer = NULL; - if (curXFBBuffer) + if (binding.get() != nullptr) { - Buffer11 *storage = Buffer11::makeBuffer11(curXFBBuffer->getImplementation()); + Buffer11 *storage = GetImplAs(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 &binding = transformFeedback->getIndexedBuffer(i); + if (binding.get() != nullptr) { - Buffer11 *storage = Buffer11::makeBuffer11(curXFBBuffer->getImplementation()); + Buffer11 *storage = GetImplAs(binding.get()); ID3D11Buffer *d3dBuffer = storage->getBuffer(BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK); - mCurrentD3DOffsets[i] = (mAppliedTFBuffers[i] != d3dBuffer || mAppliedTFOffsets[i] != curXFBOffset) ? - static_cast(curXFBOffset) : -1; + mCurrentD3DOffsets[i] = (mAppliedTFBuffers[i] != d3dBuffer || mAppliedTFOffsets[i] != binding.getOffset()) ? + static_cast(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(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(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(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(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(geometryShader); - ASSERT(geometryShader); - mDeviceContext->GSSetShader(geometryShader, NULL, 0); + ID3D11PixelShader *pixelShader = GetAs(pixelExe)->getPixelShader(); + ASSERT(reinterpret_cast(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(geometryExe)->getGeometryShader() : NULL); + mAppliedGeometryShader = reinterpret_cast(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(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(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(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(count) + 1) * sizeof(unsigned int); + GetLineLoopIndices(indices, type, static_cast(count), + data.state->isPrimitiveRestartEnabled(), &mScratchIndexDataBuffer); + + unsigned int spaceNeeded = + static_cast(sizeof(GLuint) * mScratchIndexDataBuffer.size()); gl::Error error = mLineLoopIB->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_INT); if (error.isError()) { @@ -1684,73 +1906,62 @@ gl::Error Renderer11::drawLineLoop(GLsizei count, GLenum type, const GLvoid *ind void* mappedMemory = NULL; unsigned int offset; - error = mLineLoopIB->mapBuffer(spaceNeeded, &mappedMemory, &offset); - if (error.isError()) - { - return error; - } - - unsigned int *data = reinterpret_cast(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(indices)[i]; - } - data[count] = static_cast(indices)[0]; - break; - case GL_UNSIGNED_SHORT: - for (int i = 0; i < count; i++) - { - data[i] = static_cast(indices)[i]; - } - data[count] = static_cast(indices)[0]; - break; - case GL_UNSIGNED_INT: - for (int i = 0; i < count; i++) - { - data[i] = static_cast(indices)[i]; - } - data[count] = static_cast(indices)[0]; - break; - default: UNREACHABLE(); + error = mLineLoopIB->mapBuffer(spaceNeeded, &mappedMemory, &offset); + if (error.isError()) + { + return error; } + // Copy over the converted index data. + memcpy(mappedMemory, &mScratchIndexDataBuffer[0], + sizeof(GLuint) * mScratchIndexDataBuffer.size()); + error = mLineLoopIB->unmapBuffer(); if (error.isError()) { return error; } - IndexBuffer11 *indexBuffer = IndexBuffer11::makeIndexBuffer11(mLineLoopIB->getIndexBuffer()); + IndexBuffer11 *indexBuffer = GetAs(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(indexInfo->indexRange.start) : 0); + UINT indexCount = static_cast(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::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(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(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(indices)[0]; - data[i*3 + 1] = static_cast(indices)[i + 1]; - data[i*3 + 2] = static_cast(indices)[i + 2]; - } - break; - case GL_UNSIGNED_SHORT: - for (unsigned int i = 0; i < numTris; i++) - { - data[i*3 + 0] = static_cast(indices)[0]; - data[i*3 + 1] = static_cast(indices)[i + 1]; - data[i*3 + 2] = static_cast(indices)[i + 2]; - } - break; - case GL_UNSIGNED_INT: - for (unsigned int i = 0; i < numTris; i++) - { - data[i*3 + 0] = static_cast(indices)[0]; - data[i*3 + 1] = static_cast(indices)[i + 1]; - data[i*3 + 2] = static_cast(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(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(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(program); + ProgramD3D *programD3D = GetImplAs(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(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(pixelExe)->getPixelShader() : NULL); } ID3D11GeometryShader *geometryShader = NULL; + bool transformFeedbackActive = data.state->isTransformFeedbackActiveUnpaused(); if (transformFeedbackActive) { - geometryShader = (vertexExe ? ShaderExecutable11::makeShaderExecutable11(vertexExe)->getStreamOutShader() : NULL); + geometryShader = (vertexExe ? GetAs(vertexExe)->getStreamOutShader() : NULL); } - else if (mCurRasterState.pointDrawMode) + else { - geometryShader = (geometryExe ? ShaderExecutable11::makeShaderExecutable11(geometryExe)->getGeometryShader() : NULL); + geometryShader = (geometryExe ? GetAs(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 &uniformArray) +gl::Error Renderer11::applyUniforms(const ProgramD3D &programD3D, + GLenum drawMode, + const std::vector &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(&program); - const UniformStorage11 *vertexUniformStorage = UniformStorage11::makeUniformStorage11(&programD3D->getVertexUniformStorage()); - const UniformStorage11 *fragmentUniformStorage = UniformStorage11::makeUniformStorage11(&programD3D->getFragmentUniformStorage()); + const UniformStorage11 *vertexUniformStorage = + GetAs(&programD3D.getVertexUniformStorage()); + const UniformStorage11 *fragmentUniformStorage = + GetAs(&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; + TRACE_EVENT0("gpu.angle", "Renderer11::markAllStateDirty"); - // 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()); - - 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(-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(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(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(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(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(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(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(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(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(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(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(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(source); + RenderTarget11 *dest11 = GetAs(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 &transformFeedbackVaryings, - bool separatedOutputBuffers, ShaderExecutableD3D **outExecutable) +gl::Error Renderer11::loadExecutable(const void *function, + size_t length, + ShaderType type, + const std::vector &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 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(streamOutVarying.componentCount); + entry.OutputSlot = static_cast( + (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(length), soDeclaration.data(), + static_cast(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 &transformFeedbackVaryings, - bool separatedOutputBuffers, const D3DCompilerWorkarounds &workarounds, +gl::Error Renderer11::compileToExecutable(gl::InfoLog &infoLog, + const std::string &shaderHLSL, + ShaderType type, + const std::vector &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(dest); + Image11 *src11 = GetAs(src); return Image11::generateMipmap(dest11, src11); } +gl::Error Renderer11::generateMipmapsUsingD3D(TextureStorage *storage, + const gl::TextureState &textureState) +{ + TextureStorage11 *storage11 = GetAs(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(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(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(textureDesc.Width)); - safeArea.y = gl::clamp(area.y, 0, static_cast(textureDesc.Height)); - safeArea.width = gl::clamp(area.width + std::min(area.x, 0), 0, - static_cast(textureDesc.Width) - safeArea.x); - safeArea.height = gl::clamp(area.height + std::min(area.y, 0), 0, - static_cast(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(textureDesc.Width)); - ASSERT(safeArea.y + safeArea.height <= static_cast(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(texSize.width); + resolveDesc.Height = static_cast(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(safeArea.x + safeArea.width); srcBox.top = static_cast(safeArea.y); srcBox.bottom = static_cast(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(srcAttachment.layer()); + } + srcBox.back = srcBox.front + 1; + + mDeviceContext->CopySubresourceRegion(stagingHelper.getResource(), 0, 0, 0, 0, + srcTexture->getResource(), sourceSubResource, &srcBox); - SafeRelease(srcTex); + if (invertTexture) + { + gl::PixelPackState invertTexturePack; - PackPixelsParams packParams(safeArea, format, type, outputPitch, pack, 0); - gl::Error error = packPixels(stagingTex, packParams, pixels); + // 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; - SafeRelease(stagingTex); + PackPixelsParams packParams(safeArea, format, type, outputPitch, invertTexturePack, 0); + error = packPixels(stagingHelper, packParams, pixelsOut); - return error; + 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 ¶ms, uint8_t *pixelsOut) +gl::Error Renderer11::packPixels(const TextureHelper11 &textureHelper, + const PackPixelsParams ¶ms, + 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(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 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(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(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(drawRectIn.width) / static_cast(readRectIn.width); + return static_cast(round(static_cast(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(drawRectIn.height) / static_cast(readRectIn.height); + return static_cast(round(static_cast(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 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(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 ¤tSRVs = (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(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(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(mDevice), + EGL_D3D11_DEVICE_ANGLE, EGL_FALSE); - record.srv = reinterpret_cast(srv); - if (srv) - { - record.resource = reinterpret_cast(GetViewResource(srv)); - srv->GetDesc(&record.desc); - } - else + if (error.isError()) { - record.resource = 0; + SafeDelete(mEGLDevice); + return error; } } + + *device = static_cast(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 &vertexUniformBuffers, + const std::vector &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 &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 &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 &transformFeedbackVaryings, - bool separatedOutputBuffers, ShaderExecutableD3D **outExecutable); - virtual gl::Error compileToExecutable(gl::InfoLog &infoLog, const std::string &shaderHLSL, ShaderType type, - const std::vector &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 &streamOutVaryings, + bool separatedOutputBuffers, + ShaderExecutableD3D **outExecutable) override; + gl::Error compileToExecutable(gl::InfoLog &infoLog, + const std::string &shaderHLSL, + ShaderType type, + const std::vector &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 ¶ms, uint8_t *pixelsOut); + gl::Error packPixels(const TextureHelper11 &textureHelper, + const PackPixelsParams ¶ms, + 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 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 mForceSetVertexSamplerStates; @@ -281,42 +367,7 @@ class Renderer11 : public RendererD3D std::vector mForceSetPixelSamplerStates; std::vector mCurPixelSamplerStates; - // Currently applied textures - struct SRVRecord - { - uintptr_t srv; - uintptr_t resource; - D3D11_SHADER_RESOURCE_VIEW_DESC desc; - }; - std::vector mCurVertexSRVs; - std::vector 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 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 mScratchIndexDataBuffer; - DebugAnnotator11 mAnnotator; + mutable Optional 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(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(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(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(srv); + if (srv) + { + record->resource = reinterpret_cast(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(-1); + mCurDepthStencilState.stencilBackFunc = GL_ALWAYS; + mCurDepthStencilState.stencilBackMask = static_cast(-1); + mCurDepthStencilState.stencilBackFail = GL_KEEP; + mCurDepthStencilState.stencilBackPassDepthFail = GL_KEEP; + mCurDepthStencilState.stencilBackPassDepthPass = GL_KEEP; + mCurDepthStencilState.stencilBackWritemask = static_cast(-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(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(caps->maxViewportWidth); + int dxMaxViewportBoundsY = static_cast(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(mViewportBounds.width); + dxMaxViewportBoundsY = static_cast(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(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(mCurPresentPathFastColorBufferHeight - + dxViewportTopLeftY - dxViewportHeight); + } + else + { + dxViewport.TopLeftY = static_cast(dxViewportTopLeftY); + } + + dxViewport.Width = static_cast(dxViewportWidth); + dxViewport.Height = static_cast(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((viewport.width - dxViewportWidth) + + 2 * (viewport.x - dxViewportTopLeftX)) / + dxViewport.Width; + mVertexConstants.viewAdjust[1] = static_cast((viewport.height - dxViewportHeight) + + 2 * (viewport.y - dxViewportTopLeftY)) / + dxViewport.Height; + mVertexConstants.viewAdjust[2] = static_cast(viewport.width) / dxViewport.Width; + mVertexConstants.viewAdjust[3] = static_cast(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(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(renderTargets[rtIndex]); + } + mAppliedDSV = reinterpret_cast(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 ¤tSRVs = (shaderType == gl::SAMPLER_VERTEX ? mCurVertexSRVs : mCurPixelSRVs); + + ASSERT(static_cast(resourceSlot) < currentSRVs.size()); + const SRVRecord &record = currentSRVs[resourceSlot]; + + if (record.srv != reinterpret_cast(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 ¤tSRVs = (samplerType == gl::SAMPLER_VERTEX ? mCurVertexSRVs : mCurPixelSRVs); + + gl::Range 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(rangeStart), + static_cast(rangeEnd - rangeStart), + &mNullSRVs[0]); + } + else + { + deviceContext->PSSetShaderResources(static_cast(rangeStart), + static_cast(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 ¤tSRVs = (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(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(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(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(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 + +#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 mCurDisableDepth; + Optional 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 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 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 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 + +#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(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(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(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(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(mWidth); + viewport.Height = static_cast(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, ¶ms); + } + else + { + RECT rect = {static_cast(x), static_cast(mHeight - y - height), + static_cast(x + width), static_cast(mHeight - y)}; + DXGI_PRESENT_PARAMETERS params = {1, &rect, nullptr, nullptr}; + result = mSwapChain1->Present1(swapInterval, 0, ¶ms); + } + } + 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(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(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(source)->getShaderResourceView(); + ID3D11RenderTargetView *destRTV = GetAs(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(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(image->getHeight()); int depth = destBox ? destBox->depth : static_cast(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(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(storage); -} - gl::Error TextureStorage11_2D::copyToStorage(TextureStorage *destStorage) { ASSERT(destStorage); - TextureStorage11_2D *dest11 = TextureStorage11_2D::makeTextureStorage11_2D(destStorage); + TextureStorage11_2D *dest11 = GetAs(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(renderTargetD3D); + mCurrentRenderTarget = reinterpret_cast(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(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(renderTarget11)) + { + clearSRVCache(); + mCurrentRenderTarget = reinterpret_cast(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(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(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(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(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(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 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(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 ¤tValue, - 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(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(buffer); - error = storage->getData(&input); - if (error.isError()) - { - return error; - } - input += static_cast(attrib.offset); - } - else - { - input = static_cast(attrib.pointer); - } - } - else - { - input = reinterpret_cast(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(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::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 ¤tValue, - 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(data | negativeMask); } else { - *intOutput = data; + *intOutput = static_cast(data); } } else { GLushort *uintOutput = reinterpret_cast(output); - *uintOutput = data; + *uintOutput = static_cast(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 +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(colorInfo.redBits); + info.greenBits = static_cast(colorInfo.greenBits); + info.blueBits = static_cast(colorInfo.blueBits); + info.alphaBits = static_cast(colorInfo.alphaBits); + info.sharedBits = static_cast(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, ReadColor); - AddDXGIFormat(&map, DXGI_FORMAT_R8_UNORM, 8, 1, 1, GL_UNSIGNED_NORMALIZED, GenerateMip, ReadColor); - AddDXGIFormat(&map, DXGI_FORMAT_R8G8_UNORM, 16, 1, 1, GL_UNSIGNED_NORMALIZED, GenerateMip, ReadColor); - AddDXGIFormat(&map, DXGI_FORMAT_R8G8B8A8_UNORM, 32, 1, 1, GL_UNSIGNED_NORMALIZED, GenerateMip, ReadColor); - AddDXGIFormat(&map, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, 32, 1, 1, GL_UNSIGNED_NORMALIZED, GenerateMip, ReadColor); - AddDXGIFormat(&map, DXGI_FORMAT_B8G8R8A8_UNORM, 32, 1, 1, GL_UNSIGNED_NORMALIZED, GenerateMip, ReadColor); - - AddDXGIFormat(&map, DXGI_FORMAT_R8_SNORM, 8, 1, 1, GL_SIGNED_NORMALIZED, GenerateMip, ReadColor); - AddDXGIFormat(&map, DXGI_FORMAT_R8G8_SNORM, 16, 1, 1, GL_SIGNED_NORMALIZED, GenerateMip, ReadColor); - AddDXGIFormat(&map, DXGI_FORMAT_R8G8B8A8_SNORM, 32, 1, 1, GL_SIGNED_NORMALIZED, GenerateMip, ReadColor); - - AddDXGIFormat(&map, DXGI_FORMAT_R8_UINT, 8, 1, 1, GL_UNSIGNED_INT, GenerateMip, ReadColor); - AddDXGIFormat(&map, DXGI_FORMAT_R16_UINT, 16, 1, 1, GL_UNSIGNED_INT, GenerateMip, ReadColor); - AddDXGIFormat(&map, DXGI_FORMAT_R32_UINT, 32, 1, 1, GL_UNSIGNED_INT, GenerateMip, ReadColor); - AddDXGIFormat(&map, DXGI_FORMAT_R8G8_UINT, 16, 1, 1, GL_UNSIGNED_INT, GenerateMip, ReadColor); - AddDXGIFormat(&map, DXGI_FORMAT_R16G16_UINT, 32, 1, 1, GL_UNSIGNED_INT, GenerateMip, ReadColor); - AddDXGIFormat(&map, DXGI_FORMAT_R32G32_UINT, 64, 1, 1, GL_UNSIGNED_INT, GenerateMip, ReadColor); - AddDXGIFormat(&map, DXGI_FORMAT_R32G32B32_UINT, 96, 1, 1, GL_UNSIGNED_INT, GenerateMip, ReadColor); - AddDXGIFormat(&map, DXGI_FORMAT_R8G8B8A8_UINT, 32, 1, 1, GL_UNSIGNED_INT, GenerateMip, ReadColor); - AddDXGIFormat(&map, DXGI_FORMAT_R16G16B16A16_UINT, 64, 1, 1, GL_UNSIGNED_INT, GenerateMip, ReadColor); - AddDXGIFormat(&map, DXGI_FORMAT_R32G32B32A32_UINT, 128, 1, 1, GL_UNSIGNED_INT, GenerateMip, ReadColor); - - AddDXGIFormat(&map, DXGI_FORMAT_R8_SINT, 8, 1, 1, GL_INT, GenerateMip, ReadColor); - AddDXGIFormat(&map, DXGI_FORMAT_R16_SINT, 16, 1, 1, GL_INT, GenerateMip, ReadColor); - AddDXGIFormat(&map, DXGI_FORMAT_R32_SINT, 32, 1, 1, GL_INT, GenerateMip, ReadColor); - AddDXGIFormat(&map, DXGI_FORMAT_R8G8_SINT, 16, 1, 1, GL_INT, GenerateMip, ReadColor); - AddDXGIFormat(&map, DXGI_FORMAT_R16G16_SINT, 32, 1, 1, GL_INT, GenerateMip, ReadColor); - AddDXGIFormat(&map, DXGI_FORMAT_R32G32_SINT, 64, 1, 1, GL_INT, GenerateMip, ReadColor); - AddDXGIFormat(&map, DXGI_FORMAT_R32G32B32_SINT, 96, 1, 1, GL_INT, GenerateMip, ReadColor); - AddDXGIFormat(&map, DXGI_FORMAT_R8G8B8A8_SINT, 32, 1, 1, GL_INT, GenerateMip, ReadColor); - AddDXGIFormat(&map, DXGI_FORMAT_R16G16B16A16_SINT, 64, 1, 1, GL_INT, GenerateMip, ReadColor); - AddDXGIFormat(&map, DXGI_FORMAT_R32G32B32A32_SINT, 128, 1, 1, GL_INT, GenerateMip, ReadColor); - - AddDXGIFormat(&map, DXGI_FORMAT_R10G10B10A2_UNORM, 32, 1, 1, GL_UNSIGNED_NORMALIZED, GenerateMip, ReadColor); - AddDXGIFormat(&map, DXGI_FORMAT_R10G10B10A2_UINT, 32, 1, 1, GL_UNSIGNED_INT, GenerateMip, ReadColor); - - AddDXGIFormat(&map, DXGI_FORMAT_R16_FLOAT, 16, 1, 1, GL_FLOAT, GenerateMip, ReadColor); - AddDXGIFormat(&map, DXGI_FORMAT_R16G16_FLOAT, 32, 1, 1, GL_FLOAT, GenerateMip, ReadColor); - AddDXGIFormat(&map, DXGI_FORMAT_R16G16B16A16_FLOAT, 64, 1, 1, GL_FLOAT, GenerateMip, ReadColor); - - AddDXGIFormat(&map, DXGI_FORMAT_R32_FLOAT, 32, 1, 1, GL_FLOAT, GenerateMip, ReadColor); - AddDXGIFormat(&map, DXGI_FORMAT_R32G32_FLOAT, 64, 1, 1, GL_FLOAT, GenerateMip, ReadColor); - 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, ReadColor); - - AddDXGIFormat(&map, DXGI_FORMAT_R9G9B9E5_SHAREDEXP, 32, 1, 1, GL_FLOAT, GenerateMip, ReadColor); - AddDXGIFormat(&map, DXGI_FORMAT_R11G11B10_FLOAT, 32, 1, 1, GL_FLOAT, GenerateMip, ReadColor); - - 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, ReadColor, RequiresFeatureLevel); + AddDXGIFormat(&map, DXGI_FORMAT_R8_UNORM, 8, 1, 1, GL_UNSIGNED_NORMALIZED, GenerateMip, ReadColor, RequiresFeatureLevel); + AddDXGIFormat(&map, DXGI_FORMAT_R8G8_UNORM, 16, 1, 1, GL_UNSIGNED_NORMALIZED, GenerateMip, ReadColor, RequiresFeatureLevel); + AddDXGIFormat(&map, DXGI_FORMAT_R8G8B8A8_UNORM, 32, 1, 1, GL_UNSIGNED_NORMALIZED, GenerateMip, ReadColor, RequiresFeatureLevel); + AddDXGIFormat(&map, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, 32, 1, 1, GL_UNSIGNED_NORMALIZED, GenerateMip, ReadColor, RequiresFeatureLevel); + AddDXGIFormat(&map, DXGI_FORMAT_B8G8R8A8_UNORM, 32, 1, 1, GL_UNSIGNED_NORMALIZED, GenerateMip, ReadColor, RequiresFeatureLevel); + + AddDXGIFormat(&map, DXGI_FORMAT_R8_SNORM, 8, 1, 1, GL_SIGNED_NORMALIZED, GenerateMip, ReadColor , RequiresFeatureLevel); + AddDXGIFormat(&map, DXGI_FORMAT_R8G8_SNORM, 16, 1, 1, GL_SIGNED_NORMALIZED, GenerateMip, ReadColor , RequiresFeatureLevel); + AddDXGIFormat(&map, DXGI_FORMAT_R8G8B8A8_SNORM, 32, 1, 1, GL_SIGNED_NORMALIZED, GenerateMip, ReadColor, RequiresFeatureLevel); + + AddDXGIFormat(&map, DXGI_FORMAT_R8_UINT, 8, 1, 1, GL_UNSIGNED_INT, GenerateMip, ReadColor, NeverSupported); + AddDXGIFormat(&map, DXGI_FORMAT_R16_UINT, 16, 1, 1, GL_UNSIGNED_INT, GenerateMip, ReadColor, NeverSupported); + AddDXGIFormat(&map, DXGI_FORMAT_R32_UINT, 32, 1, 1, GL_UNSIGNED_INT, GenerateMip, ReadColor, NeverSupported); + AddDXGIFormat(&map, DXGI_FORMAT_R8G8_UINT, 16, 1, 1, GL_UNSIGNED_INT, GenerateMip, ReadColor, NeverSupported); + AddDXGIFormat(&map, DXGI_FORMAT_R16G16_UINT, 32, 1, 1, GL_UNSIGNED_INT, GenerateMip, ReadColor, NeverSupported); + AddDXGIFormat(&map, DXGI_FORMAT_R32G32_UINT, 64, 1, 1, GL_UNSIGNED_INT, GenerateMip, ReadColor, NeverSupported); + AddDXGIFormat(&map, DXGI_FORMAT_R32G32B32_UINT, 96, 1, 1, GL_UNSIGNED_INT, GenerateMip, ReadColor, NeverSupported); + AddDXGIFormat(&map, DXGI_FORMAT_R8G8B8A8_UINT, 32, 1, 1, GL_UNSIGNED_INT, GenerateMip, ReadColor, NeverSupported); + AddDXGIFormat(&map, DXGI_FORMAT_R16G16B16A16_UINT, 64, 1, 1, GL_UNSIGNED_INT, GenerateMip, ReadColor, NeverSupported); + AddDXGIFormat(&map, DXGI_FORMAT_R32G32B32A32_UINT, 128, 1, 1, GL_UNSIGNED_INT, GenerateMip, ReadColor, NeverSupported); + + AddDXGIFormat(&map, DXGI_FORMAT_R8_SINT, 8, 1, 1, GL_INT, GenerateMip, ReadColor, NeverSupported); + AddDXGIFormat(&map, DXGI_FORMAT_R16_SINT, 16, 1, 1, GL_INT, GenerateMip, ReadColor, NeverSupported); + AddDXGIFormat(&map, DXGI_FORMAT_R32_SINT, 32, 1, 1, GL_INT, GenerateMip, ReadColor, NeverSupported); + AddDXGIFormat(&map, DXGI_FORMAT_R8G8_SINT, 16, 1, 1, GL_INT, GenerateMip, ReadColor, NeverSupported); + AddDXGIFormat(&map, DXGI_FORMAT_R16G16_SINT, 32, 1, 1, GL_INT, GenerateMip, ReadColor, NeverSupported); + AddDXGIFormat(&map, DXGI_FORMAT_R32G32_SINT, 64, 1, 1, GL_INT, GenerateMip, ReadColor, NeverSupported); + AddDXGIFormat(&map, DXGI_FORMAT_R32G32B32_SINT, 96, 1, 1, GL_INT, GenerateMip, ReadColor, NeverSupported); + AddDXGIFormat(&map, DXGI_FORMAT_R8G8B8A8_SINT, 32, 1, 1, GL_INT, GenerateMip, ReadColor, NeverSupported); + AddDXGIFormat(&map, DXGI_FORMAT_R16G16B16A16_SINT, 64, 1, 1, GL_INT, GenerateMip, ReadColor, NeverSupported); + AddDXGIFormat(&map, DXGI_FORMAT_R32G32B32A32_SINT, 128, 1, 1, GL_INT, GenerateMip, ReadColor, NeverSupported); + + AddDXGIFormat(&map, DXGI_FORMAT_R10G10B10A2_UNORM, 32, 1, 1, GL_UNSIGNED_NORMALIZED, GenerateMip, ReadColor, RequiresFeatureLevel); + AddDXGIFormat(&map, DXGI_FORMAT_R10G10B10A2_UINT, 32, 1, 1, GL_UNSIGNED_INT, GenerateMip, ReadColor, NeverSupported); + + AddDXGIFormat(&map, DXGI_FORMAT_R16_FLOAT, 16, 1, 1, GL_FLOAT, GenerateMip, ReadColor, RequiresFeatureLevel); + AddDXGIFormat(&map, DXGI_FORMAT_R16G16_FLOAT, 32, 1, 1, GL_FLOAT, GenerateMip, ReadColor, RequiresFeatureLevel); + AddDXGIFormat(&map, DXGI_FORMAT_R16G16B16A16_FLOAT, 64, 1, 1, GL_FLOAT, GenerateMip, ReadColor, RequiresFeatureLevel); + + AddDXGIFormat(&map, DXGI_FORMAT_R32_FLOAT, 32, 1, 1, GL_FLOAT, GenerateMip, ReadColor, RequiresFeatureLevel); + AddDXGIFormat(&map, DXGI_FORMAT_R32G32_FLOAT, 64, 1, 1, GL_FLOAT, GenerateMip, ReadColor, RequiresFeatureLevel); + 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, ReadColor, RequiresFeatureLevel); + + AddDXGIFormat(&map, DXGI_FORMAT_R9G9B9E5_SHAREDEXP, 32, 1, 1, GL_FLOAT, GenerateMip, ReadColor, NeverSupported); + AddDXGIFormat(&map, DXGI_FORMAT_R11G11B10_FLOAT, 32, 1, 1, GL_FLOAT, GenerateMip, ReadColor, RequiresFeatureLevel); + + 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, ReadColor, RequiresFeatureLevel); + AddDXGIFormat(&map, DXGI_FORMAT_B4G4R4A4_UNORM, 16, 1, 1, GL_UNSIGNED_NORMALIZED, GenerateMip, ReadColor, NeverSupported); + AddDXGIFormat(&map, DXGI_FORMAT_B5G5R5A1_UNORM, 16, 1, 1, GL_UNSIGNED_NORMALIZED, GenerateMip, ReadColor, 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 SwizzleInfoMap; -typedef std::pair 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 InternalFormatInitializerPair; -typedef std::map InternalFormatInitializerMap; - -static InternalFormatInitializerMap BuildInternalFormatInitializerMap() -{ - InternalFormatInitializerMap map; - - map.insert(InternalFormatInitializerPair(GL_RGB8, Initialize4ComponentData )); - map.insert(InternalFormatInitializerPair(GL_RGB565, Initialize4ComponentData )); - map.insert(InternalFormatInitializerPair(GL_SRGB8, Initialize4ComponentData )); - map.insert(InternalFormatInitializerPair(GL_RGB16F, Initialize4ComponentData)); - map.insert(InternalFormatInitializerPair(GL_RGB32F, Initialize4ComponentData)); - map.insert(InternalFormatInitializerPair(GL_RGB8UI, Initialize4ComponentData )); - map.insert(InternalFormatInitializerPair(GL_RGB8I, Initialize4ComponentData )); - map.insert(InternalFormatInitializerPair(GL_RGB16UI, Initialize4ComponentData )); - map.insert(InternalFormatInitializerPair(GL_RGB16I, Initialize4ComponentData )); - map.insert(InternalFormatInitializerPair(GL_RGB32UI, Initialize4ComponentData )); - map.insert(InternalFormatInitializerPair(GL_RGB32I, Initialize4ComponentData )); - - 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 TypeLoadFunctionPair; -typedef std::map > 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); - - return map; -} - -D3D11LoadFunctionMap BuildBaseD3D11LoadFunctionMap() -{ - D3D11LoadFunctionMap map; - - // | Internal format | Type | Load function | - InsertLoadFunction(&map, GL_RGBA8, GL_UNSIGNED_BYTE, LoadToNative ); - InsertLoadFunction(&map, GL_RGB5_A1, GL_UNSIGNED_BYTE, LoadToNative ); - InsertLoadFunction(&map, GL_RGBA4, GL_UNSIGNED_BYTE, LoadToNative ); - InsertLoadFunction(&map, GL_SRGB8_ALPHA8, GL_UNSIGNED_BYTE, LoadToNative ); - InsertLoadFunction(&map, GL_RGBA8_SNORM, GL_BYTE, LoadToNative ); - 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 ); - 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 ); - InsertLoadFunction(&map, GL_RGBA16F, GL_HALF_FLOAT_OES, LoadToNative ); - InsertLoadFunction(&map, GL_RGBA32F, GL_FLOAT, LoadToNative ); - InsertLoadFunction(&map, GL_RGBA16F, GL_FLOAT, Load32FTo16F<4> ); - InsertLoadFunction(&map, GL_RGBA8UI, GL_UNSIGNED_BYTE, LoadToNative ); - InsertLoadFunction(&map, GL_RGBA8I, GL_BYTE, LoadToNative ); - InsertLoadFunction(&map, GL_RGBA16UI, GL_UNSIGNED_SHORT, LoadToNative ); - InsertLoadFunction(&map, GL_RGBA16I, GL_SHORT, LoadToNative ); - InsertLoadFunction(&map, GL_RGBA32UI, GL_UNSIGNED_INT, LoadToNative ); - InsertLoadFunction(&map, GL_RGBA32I, GL_INT, LoadToNative ); - InsertLoadFunction(&map, GL_RGB10_A2UI, GL_UNSIGNED_INT_2_10_10_10_REV, LoadToNative ); - InsertLoadFunction(&map, GL_RGB8, GL_UNSIGNED_BYTE, LoadToNative3To4 ); - InsertLoadFunction(&map, GL_RGB565, GL_UNSIGNED_BYTE, LoadToNative3To4 ); - InsertLoadFunction(&map, GL_SRGB8, GL_UNSIGNED_BYTE, LoadToNative3To4 ); - InsertLoadFunction(&map, GL_RGB8_SNORM, GL_BYTE, LoadToNative3To4 ); - 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 ); - InsertLoadFunction(&map, GL_RGB9_E5, GL_UNSIGNED_INT_5_9_9_9_REV, LoadToNative ); - InsertLoadFunction(&map, GL_RGB16F, GL_HALF_FLOAT, LoadToNative3To4); - InsertLoadFunction(&map, GL_RGB16F, GL_HALF_FLOAT_OES, LoadToNative3To4); - 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); - 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 ); - InsertLoadFunction(&map, GL_RGB8I, GL_BYTE, LoadToNative3To4 ); - InsertLoadFunction(&map, GL_RGB16UI, GL_UNSIGNED_SHORT, LoadToNative3To4 ); - InsertLoadFunction(&map, GL_RGB16I, GL_SHORT, LoadToNative3To4 ); - InsertLoadFunction(&map, GL_RGB32UI, GL_UNSIGNED_INT, LoadToNative3To4 ); - InsertLoadFunction(&map, GL_RGB32I, GL_INT, LoadToNative3To4 ); - InsertLoadFunction(&map, GL_RG8, GL_UNSIGNED_BYTE, LoadToNative ); - InsertLoadFunction(&map, GL_RG8_SNORM, GL_BYTE, LoadToNative ); - InsertLoadFunction(&map, GL_RG16F, GL_HALF_FLOAT, LoadToNative ); - InsertLoadFunction(&map, GL_RG16F, GL_HALF_FLOAT_OES, LoadToNative ); - InsertLoadFunction(&map, GL_RG32F, GL_FLOAT, LoadToNative ); - InsertLoadFunction(&map, GL_RG16F, GL_FLOAT, Load32FTo16F<2> ); - InsertLoadFunction(&map, GL_RG8UI, GL_UNSIGNED_BYTE, LoadToNative ); - InsertLoadFunction(&map, GL_RG8I, GL_BYTE, LoadToNative ); - InsertLoadFunction(&map, GL_RG16UI, GL_UNSIGNED_SHORT, LoadToNative ); - InsertLoadFunction(&map, GL_RG16I, GL_SHORT, LoadToNative ); - InsertLoadFunction(&map, GL_RG32UI, GL_UNSIGNED_INT, LoadToNative ); - InsertLoadFunction(&map, GL_RG32I, GL_INT, LoadToNative ); - InsertLoadFunction(&map, GL_R8, GL_UNSIGNED_BYTE, LoadToNative ); - InsertLoadFunction(&map, GL_R8_SNORM, GL_BYTE, LoadToNative ); - InsertLoadFunction(&map, GL_R16F, GL_HALF_FLOAT, LoadToNative ); - InsertLoadFunction(&map, GL_R16F, GL_HALF_FLOAT_OES, LoadToNative ); - InsertLoadFunction(&map, GL_R32F, GL_FLOAT, LoadToNative ); - InsertLoadFunction(&map, GL_R16F, GL_FLOAT, Load32FTo16F<1> ); - InsertLoadFunction(&map, GL_R8UI, GL_UNSIGNED_BYTE, LoadToNative ); - InsertLoadFunction(&map, GL_R8I, GL_BYTE, LoadToNative ); - InsertLoadFunction(&map, GL_R16UI, GL_UNSIGNED_SHORT, LoadToNative ); - InsertLoadFunction(&map, GL_R16I, GL_SHORT, LoadToNative ); - InsertLoadFunction(&map, GL_R32UI, GL_UNSIGNED_INT, LoadToNative ); - InsertLoadFunction(&map, GL_R32I, GL_INT, LoadToNative ); - InsertLoadFunction(&map, GL_DEPTH_COMPONENT16, GL_UNSIGNED_SHORT, LoadToNative ); - 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 ); - 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 ); - - // 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 ); - InsertLoadFunction(&map, GL_BGRA4_ANGLEX, GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT, LoadRGBA4ToRGBA8 ); - InsertLoadFunction(&map, GL_BGRA4_ANGLEX, GL_UNSIGNED_BYTE, LoadToNative ); - 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 ); - - // 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 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 &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 &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 D3D11VertexFormatInfoMap; -typedef std::pair D3D11VertexFormatPair; +typedef std::map D3D11VertexFormatInfoMap; +typedef std::pair 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); - AddVertexFormatInfo(&map, GL_BYTE, GL_FALSE, 2, VERTEX_CONVERT_GPU, DXGI_FORMAT_R8G8_SINT, &CopyNativeVertexData); - AddVertexFormatInfo(&map, GL_BYTE, GL_FALSE, 3, VERTEX_CONVERT_BOTH, DXGI_FORMAT_R8G8B8A8_SINT, &CopyNativeVertexData); - AddVertexFormatInfo(&map, GL_BYTE, GL_FALSE, 4, VERTEX_CONVERT_GPU, DXGI_FORMAT_R8G8B8A8_SINT, &CopyNativeVertexData); + // GL_BYTE -- un-normalized + case gl::VERTEX_FORMAT_SBYTE1: + { + static const VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R8_SINT, &CopyNativeVertexData); + return info; + } + case gl::VERTEX_FORMAT_SBYTE2: + { + static const VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R8G8_SINT, &CopyNativeVertexData); + return info; + } + case gl::VERTEX_FORMAT_SBYTE3: + { + static const VertexFormat info(VERTEX_CONVERT_BOTH, DXGI_FORMAT_R8G8B8A8_SINT, &CopyNativeVertexData); + return info; + } + case gl::VERTEX_FORMAT_SBYTE4: + { + static const VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R8G8B8A8_SINT, &CopyNativeVertexData); + return info; + } - // GL_BYTE -- normalized - AddVertexFormatInfo(&map, GL_BYTE, GL_TRUE, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8_SNORM, &CopyNativeVertexData); - AddVertexFormatInfo(&map, GL_BYTE, GL_TRUE, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8_SNORM, &CopyNativeVertexData); - AddVertexFormatInfo(&map, GL_BYTE, GL_TRUE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R8G8B8A8_SNORM, &CopyNativeVertexData); - AddVertexFormatInfo(&map, GL_BYTE, GL_TRUE, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8B8A8_SNORM, &CopyNativeVertexData); + // GL_BYTE -- normalized + case gl::VERTEX_FORMAT_SBYTE1_NORM: + { + static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R8_SNORM, &CopyNativeVertexData); + return info; + } + case gl::VERTEX_FORMAT_SBYTE2_NORM: + { + static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8_SNORM, &CopyNativeVertexData); + return info; + } + case gl::VERTEX_FORMAT_SBYTE3_NORM: + { + static const VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R8G8B8A8_SNORM, &CopyNativeVertexData); + return info; + } + case gl::VERTEX_FORMAT_SBYTE4_NORM: + { + static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8B8A8_SNORM, &CopyNativeVertexData); + return info; + } - // GL_UNSIGNED_BYTE -- un-normalized - AddVertexFormatInfo(&map, GL_UNSIGNED_BYTE, GL_FALSE, 1, VERTEX_CONVERT_GPU, DXGI_FORMAT_R8_UINT, &CopyNativeVertexData); - AddVertexFormatInfo(&map, GL_UNSIGNED_BYTE, GL_FALSE, 2, VERTEX_CONVERT_GPU, DXGI_FORMAT_R8G8_UINT, &CopyNativeVertexData); - AddVertexFormatInfo(&map, GL_UNSIGNED_BYTE, GL_FALSE, 3, VERTEX_CONVERT_BOTH, DXGI_FORMAT_R8G8B8A8_UINT, &CopyNativeVertexData); - AddVertexFormatInfo(&map, GL_UNSIGNED_BYTE, GL_FALSE, 4, VERTEX_CONVERT_GPU, DXGI_FORMAT_R8G8B8A8_UINT, &CopyNativeVertexData); + // GL_UNSIGNED_BYTE -- un-normalized + case gl::VERTEX_FORMAT_UBYTE1: + { + static const VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R8_UINT, &CopyNativeVertexData); + return info; + } + case gl::VERTEX_FORMAT_UBYTE2: + { + static const VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R8G8_UINT, &CopyNativeVertexData); + return info; + } + case gl::VERTEX_FORMAT_UBYTE3: + { + static const VertexFormat info(VERTEX_CONVERT_BOTH, DXGI_FORMAT_R8G8B8A8_UINT, &CopyNativeVertexData); + return info; + } + case gl::VERTEX_FORMAT_UBYTE4: + { + static const VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R8G8B8A8_UINT, &CopyNativeVertexData); + return info; + } - // GL_UNSIGNED_BYTE -- normalized - AddVertexFormatInfo(&map, GL_UNSIGNED_BYTE, GL_TRUE, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8_UNORM, &CopyNativeVertexData); - AddVertexFormatInfo(&map, GL_UNSIGNED_BYTE, GL_TRUE, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8_UNORM, &CopyNativeVertexData); - AddVertexFormatInfo(&map, GL_UNSIGNED_BYTE, GL_TRUE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R8G8B8A8_UNORM, &CopyNativeVertexData); - AddVertexFormatInfo(&map, GL_UNSIGNED_BYTE, GL_TRUE, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8B8A8_UNORM, &CopyNativeVertexData); + // GL_UNSIGNED_BYTE -- normalized + case gl::VERTEX_FORMAT_UBYTE1_NORM: + { + static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R8_UNORM, &CopyNativeVertexData); + return info; + } + case gl::VERTEX_FORMAT_UBYTE2_NORM: + { + static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8_UNORM, &CopyNativeVertexData); + return info; + } + case gl::VERTEX_FORMAT_UBYTE3_NORM: + { + static const VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R8G8B8A8_UNORM, &CopyNativeVertexData); + return info; + } + case gl::VERTEX_FORMAT_UBYTE4_NORM: + { + static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8B8A8_UNORM, &CopyNativeVertexData); + return info; + } - // GL_SHORT -- un-normalized - AddVertexFormatInfo(&map, GL_SHORT, GL_FALSE, 1, VERTEX_CONVERT_GPU, DXGI_FORMAT_R16_SINT, &CopyNativeVertexData); - AddVertexFormatInfo(&map, GL_SHORT, GL_FALSE, 2, VERTEX_CONVERT_GPU, DXGI_FORMAT_R16G16_SINT, &CopyNativeVertexData); - AddVertexFormatInfo(&map, GL_SHORT, GL_FALSE, 3, VERTEX_CONVERT_BOTH, DXGI_FORMAT_R16G16B16A16_SINT, &CopyNativeVertexData); - AddVertexFormatInfo(&map, GL_SHORT, GL_FALSE, 4, VERTEX_CONVERT_GPU, DXGI_FORMAT_R16G16B16A16_SINT, &CopyNativeVertexData); + // GL_SHORT -- un-normalized + case gl::VERTEX_FORMAT_SSHORT1: + { + static const VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R16_SINT, &CopyNativeVertexData); + return info; + } + case gl::VERTEX_FORMAT_SSHORT2: + { + static const VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R16G16_SINT, &CopyNativeVertexData); + return info; + } + case gl::VERTEX_FORMAT_SSHORT3: + { + static const VertexFormat info(VERTEX_CONVERT_BOTH, DXGI_FORMAT_R16G16B16A16_SINT, &CopyNativeVertexData); + return info; + } + case gl::VERTEX_FORMAT_SSHORT4: + { + static const VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R16G16B16A16_SINT, &CopyNativeVertexData); + return info; + } - // GL_SHORT -- normalized - AddVertexFormatInfo(&map, GL_SHORT, GL_TRUE, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16_SNORM, &CopyNativeVertexData); - AddVertexFormatInfo(&map, GL_SHORT, GL_TRUE, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16_SNORM, &CopyNativeVertexData); - AddVertexFormatInfo(&map, GL_SHORT, GL_TRUE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16B16A16_SNORM, &CopyNativeVertexData); - AddVertexFormatInfo(&map, GL_SHORT, GL_TRUE, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16B16A16_SNORM, &CopyNativeVertexData); + // GL_SHORT -- normalized + case gl::VERTEX_FORMAT_SSHORT1_NORM: + { + static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R16_SNORM, &CopyNativeVertexData); + return info; + } + case gl::VERTEX_FORMAT_SSHORT2_NORM: + { + static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16_SNORM, &CopyNativeVertexData); + return info; + } + case gl::VERTEX_FORMAT_SSHORT3_NORM: + { + static const VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16B16A16_SNORM, &CopyNativeVertexData); + return info; + } + case gl::VERTEX_FORMAT_SSHORT4_NORM: + { + static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16B16A16_SNORM, &CopyNativeVertexData); + return info; + } - // GL_UNSIGNED_SHORT -- un-normalized - AddVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_FALSE, 1, VERTEX_CONVERT_GPU, DXGI_FORMAT_R16_UINT, &CopyNativeVertexData); - AddVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_FALSE, 2, VERTEX_CONVERT_GPU, DXGI_FORMAT_R16G16_UINT, &CopyNativeVertexData); - AddVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_FALSE, 3, VERTEX_CONVERT_BOTH, DXGI_FORMAT_R16G16B16A16_UINT, &CopyNativeVertexData); - AddVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_FALSE, 4, VERTEX_CONVERT_GPU, DXGI_FORMAT_R16G16B16A16_UINT, &CopyNativeVertexData); + // GL_UNSIGNED_SHORT -- un-normalized + case gl::VERTEX_FORMAT_USHORT1: + { + static const VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R16_UINT, &CopyNativeVertexData); + return info; + } + case gl::VERTEX_FORMAT_USHORT2: + { + static const VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R16G16_UINT, &CopyNativeVertexData); + return info; + } + case gl::VERTEX_FORMAT_USHORT3: + { + static const VertexFormat info(VERTEX_CONVERT_BOTH, DXGI_FORMAT_R16G16B16A16_UINT, &CopyNativeVertexData); + return info; + } + case gl::VERTEX_FORMAT_USHORT4: + { + static const VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R16G16B16A16_UINT, &CopyNativeVertexData); + return info; + } - // GL_UNSIGNED_SHORT -- normalized - AddVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_TRUE, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16_UNORM, &CopyNativeVertexData); - AddVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_TRUE, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16_UNORM, &CopyNativeVertexData); - AddVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_TRUE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16B16A16_UNORM, &CopyNativeVertexData); - AddVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_TRUE, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16B16A16_UNORM, &CopyNativeVertexData); - - // GL_INT -- un-normalized - AddVertexFormatInfo(&map, GL_INT, GL_FALSE, 1, VERTEX_CONVERT_GPU, DXGI_FORMAT_R32_SINT, &CopyNativeVertexData); - AddVertexFormatInfo(&map, GL_INT, GL_FALSE, 2, VERTEX_CONVERT_GPU, DXGI_FORMAT_R32G32_SINT, &CopyNativeVertexData); - AddVertexFormatInfo(&map, GL_INT, GL_FALSE, 3, VERTEX_CONVERT_GPU, DXGI_FORMAT_R32G32B32_SINT, &CopyNativeVertexData); - AddVertexFormatInfo(&map, GL_INT, GL_FALSE, 4, VERTEX_CONVERT_GPU, DXGI_FORMAT_R32G32B32A32_SINT, &CopyNativeVertexData); - - // GL_INT -- normalized - AddVertexFormatInfo(&map, GL_INT, GL_TRUE, 1, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32_FLOAT, &CopyTo32FVertexData); - AddVertexFormatInfo(&map, GL_INT, GL_TRUE, 2, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32_FLOAT, &CopyTo32FVertexData); - AddVertexFormatInfo(&map, GL_INT, GL_TRUE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32_FLOAT, &CopyTo32FVertexData); - AddVertexFormatInfo(&map, GL_INT, GL_TRUE, 4, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32A32_FLOAT, &CopyTo32FVertexData); - - // GL_UNSIGNED_INT -- un-normalized - AddVertexFormatInfo(&map, GL_UNSIGNED_INT, GL_FALSE, 1, VERTEX_CONVERT_GPU, DXGI_FORMAT_R32_UINT, &CopyNativeVertexData); - AddVertexFormatInfo(&map, GL_UNSIGNED_INT, GL_FALSE, 2, VERTEX_CONVERT_GPU, DXGI_FORMAT_R32G32_UINT, &CopyNativeVertexData); - AddVertexFormatInfo(&map, GL_UNSIGNED_INT, GL_FALSE, 3, VERTEX_CONVERT_GPU, DXGI_FORMAT_R32G32B32_UINT, &CopyNativeVertexData); - AddVertexFormatInfo(&map, GL_UNSIGNED_INT, GL_FALSE, 4, VERTEX_CONVERT_GPU, DXGI_FORMAT_R32G32B32A32_UINT, &CopyNativeVertexData); - - // GL_UNSIGNED_INT -- normalized - AddVertexFormatInfo(&map, GL_UNSIGNED_INT, GL_TRUE, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32_FLOAT, &CopyTo32FVertexData); - AddVertexFormatInfo(&map, GL_UNSIGNED_INT, GL_TRUE, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32_FLOAT, &CopyTo32FVertexData); - AddVertexFormatInfo(&map, GL_UNSIGNED_INT, GL_TRUE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32_FLOAT, &CopyTo32FVertexData); - AddVertexFormatInfo(&map, GL_UNSIGNED_INT, GL_TRUE, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32B32A32_FLOAT, &CopyTo32FVertexData); + // GL_UNSIGNED_SHORT -- normalized + case gl::VERTEX_FORMAT_USHORT1_NORM: + { + static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R16_UNORM, &CopyNativeVertexData); + return info; + } + case gl::VERTEX_FORMAT_USHORT2_NORM: + { + static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16_UNORM, &CopyNativeVertexData); + return info; + } + case gl::VERTEX_FORMAT_USHORT3_NORM: + { + static const VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16B16A16_UNORM, &CopyNativeVertexData); + return info; + } + case gl::VERTEX_FORMAT_USHORT4_NORM: + { + static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16B16A16_UNORM, &CopyNativeVertexData); + 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); + return info; + } + case gl::VERTEX_FORMAT_SINT2: + { + static const VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R32G32_SINT, &CopyNativeVertexData); + return info; + } + case gl::VERTEX_FORMAT_SINT3: + { + static const VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R32G32B32_SINT, &CopyNativeVertexData); + return info; + } + case gl::VERTEX_FORMAT_SINT4: + { + static const VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R32G32B32A32_SINT, &CopyNativeVertexData); + return info; + } - // GL_HALF_FLOAT - AddVertexFormatInfo(&map, GL_HALF_FLOAT, GL_FALSE, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16_FLOAT, &CopyNativeVertexData); - AddVertexFormatInfo(&map, GL_HALF_FLOAT, GL_FALSE, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16_FLOAT, &CopyNativeVertexData); - AddVertexFormatInfo(&map, GL_HALF_FLOAT, GL_FALSE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16B16A16_FLOAT, &CopyNativeVertexData); - AddVertexFormatInfo(&map, GL_HALF_FLOAT, GL_FALSE, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16B16A16_FLOAT, &CopyNativeVertexData); + // GL_INT -- normalized + case gl::VERTEX_FORMAT_SINT1_NORM: + { + static const VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R32_FLOAT, &CopyTo32FVertexData); + return info; + } + case gl::VERTEX_FORMAT_SINT2_NORM: + { + static const VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32_FLOAT, &CopyTo32FVertexData); + return info; + } + case gl::VERTEX_FORMAT_SINT3_NORM: + { + static const VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32_FLOAT, &CopyTo32FVertexData); + return info; + } + case gl::VERTEX_FORMAT_SINT4_NORM: + { + static const VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32A32_FLOAT, &CopyTo32FVertexData); + return info; + } - // GL_FLOAT - AddVertexFormatInfo(&map, GL_FLOAT, GL_FALSE, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32_FLOAT, &CopyNativeVertexData); - AddVertexFormatInfo(&map, GL_FLOAT, GL_FALSE, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32_FLOAT, &CopyNativeVertexData); - AddVertexFormatInfo(&map, GL_FLOAT, GL_FALSE, 3, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32B32_FLOAT, &CopyNativeVertexData); - AddVertexFormatInfo(&map, GL_FLOAT, GL_FALSE, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32B32A32_FLOAT, &CopyNativeVertexData); - - // 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); - AddVertexFormatInfo(&map, GL_INT_2_10_10_10_REV, GL_TRUE, 4, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32A32_FLOAT, &CopyXYZ10W2ToXYZW32FVertexData); - - // 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); - AddVertexFormatInfo(&map, GL_UNSIGNED_INT_2_10_10_10_REV, GL_TRUE, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R10G10B10A2_UNORM, &CopyNativeVertexData); - - // - // Integer Formats - // - - // GL_BYTE - AddIntegerVertexFormatInfo(&map, GL_BYTE, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8_SINT, &CopyNativeVertexData); - AddIntegerVertexFormatInfo(&map, GL_BYTE, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8_SINT, &CopyNativeVertexData); - AddIntegerVertexFormatInfo(&map, GL_BYTE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R8G8B8A8_SINT, &CopyNativeVertexData); - AddIntegerVertexFormatInfo(&map, GL_BYTE, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8B8A8_SINT, &CopyNativeVertexData); - - // GL_UNSIGNED_BYTE - AddIntegerVertexFormatInfo(&map, GL_UNSIGNED_BYTE, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8_UINT, &CopyNativeVertexData); - AddIntegerVertexFormatInfo(&map, GL_UNSIGNED_BYTE, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8_UINT, &CopyNativeVertexData); - AddIntegerVertexFormatInfo(&map, GL_UNSIGNED_BYTE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R8G8B8A8_UINT, &CopyNativeVertexData); - AddIntegerVertexFormatInfo(&map, GL_UNSIGNED_BYTE, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8B8A8_UINT, &CopyNativeVertexData); - - // GL_SHORT - AddIntegerVertexFormatInfo(&map, GL_SHORT, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16_SINT, &CopyNativeVertexData); - AddIntegerVertexFormatInfo(&map, GL_SHORT, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16_SINT, &CopyNativeVertexData); - AddIntegerVertexFormatInfo(&map, GL_SHORT, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16B16A16_SINT, &CopyNativeVertexData); - AddIntegerVertexFormatInfo(&map, GL_SHORT, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16B16A16_SINT, &CopyNativeVertexData); - - // GL_UNSIGNED_SHORT - AddIntegerVertexFormatInfo(&map, GL_UNSIGNED_SHORT, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16_UINT, &CopyNativeVertexData); - AddIntegerVertexFormatInfo(&map, GL_UNSIGNED_SHORT, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16_UINT, &CopyNativeVertexData); - AddIntegerVertexFormatInfo(&map, GL_UNSIGNED_SHORT, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16B16A16_UINT, &CopyNativeVertexData); - AddIntegerVertexFormatInfo(&map, GL_UNSIGNED_SHORT, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16B16A16_UINT, &CopyNativeVertexData); - - // GL_INT - AddIntegerVertexFormatInfo(&map, GL_INT, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32_SINT, &CopyNativeVertexData); - AddIntegerVertexFormatInfo(&map, GL_INT, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32_SINT, &CopyNativeVertexData); - AddIntegerVertexFormatInfo(&map, GL_INT, 3, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32B32_SINT, &CopyNativeVertexData); - AddIntegerVertexFormatInfo(&map, GL_INT, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32B32A32_SINT, &CopyNativeVertexData); - - // GL_UNSIGNED_INT - AddIntegerVertexFormatInfo(&map, GL_UNSIGNED_INT, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32_SINT, &CopyNativeVertexData); - AddIntegerVertexFormatInfo(&map, GL_UNSIGNED_INT, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32_SINT, &CopyNativeVertexData); - AddIntegerVertexFormatInfo(&map, GL_UNSIGNED_INT, 3, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32B32_SINT, &CopyNativeVertexData); - AddIntegerVertexFormatInfo(&map, GL_UNSIGNED_INT, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32B32A32_SINT, &CopyNativeVertexData); - - // 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); - - // 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); + // GL_UNSIGNED_INT -- un-normalized + case gl::VERTEX_FORMAT_UINT1: + { + static const VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R32_UINT, &CopyNativeVertexData); + return info; + } + case gl::VERTEX_FORMAT_UINT2: + { + static const VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R32G32_UINT, &CopyNativeVertexData); + return info; + } + case gl::VERTEX_FORMAT_UINT3: + { + static const VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R32G32B32_UINT, &CopyNativeVertexData); + return info; + } + case gl::VERTEX_FORMAT_UINT4: + { + static const VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R32G32B32A32_UINT, &CopyNativeVertexData); + 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); + return info; + } + case gl::VERTEX_FORMAT_UINT2_NORM: + { + static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32_FLOAT, &CopyTo32FVertexData); + return info; + } + case gl::VERTEX_FORMAT_UINT3_NORM: + { + static const VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32_FLOAT, &CopyTo32FVertexData); + return info; + } + case gl::VERTEX_FORMAT_UINT4_NORM: + { + static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32B32A32_FLOAT, &CopyTo32FVertexData); + 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); + return info; + } + case gl::VERTEX_FORMAT_HALF2: + { + static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16_FLOAT, &CopyNativeVertexData); + return info; + } + case gl::VERTEX_FORMAT_HALF3: + { + static const VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16B16A16_FLOAT, &CopyNativeVertexData); + return info; + } + case gl::VERTEX_FORMAT_HALF4: + { + static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16B16A16_FLOAT, &CopyNativeVertexData); + 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); + return info; + } + case gl::VERTEX_FORMAT_FLOAT2: + { + static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32_FLOAT, &CopyNativeVertexData); + return info; + } + case gl::VERTEX_FORMAT_FLOAT3: + { + static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32B32_FLOAT, &CopyNativeVertexData); + return info; + } + case gl::VERTEX_FORMAT_FLOAT4: + { + static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32B32A32_FLOAT, &CopyNativeVertexData); + 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); + return info; + } + case gl::VERTEX_FORMAT_SINT210_NORM: + { + static const VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32A32_FLOAT, &CopyXYZ10W2ToXYZW32FVertexData); + 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); + return info; + } + case gl::VERTEX_FORMAT_UINT210_NORM: + { + static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R10G10B10A2_UNORM, &CopyNativeVertexData); + return info; + } + + // + // Integer Formats + // + + // GL_BYTE + case gl::VERTEX_FORMAT_SBYTE1_INT: + { + static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R8_SINT, &CopyNativeVertexData); + return info; + } + case gl::VERTEX_FORMAT_SBYTE2_INT: + { + static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8_SINT, &CopyNativeVertexData); + return info; + } + case gl::VERTEX_FORMAT_SBYTE3_INT: + { + static const VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R8G8B8A8_SINT, &CopyNativeVertexData); + return info; + } + case gl::VERTEX_FORMAT_SBYTE4_INT: + { + static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8B8A8_SINT, &CopyNativeVertexData); + return info; + } + + // GL_UNSIGNED_BYTE + case gl::VERTEX_FORMAT_UBYTE1_INT: + { + static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R8_UINT, &CopyNativeVertexData); + return info; + } + case gl::VERTEX_FORMAT_UBYTE2_INT: + { + static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8_UINT, &CopyNativeVertexData); + return info; + } + case gl::VERTEX_FORMAT_UBYTE3_INT: + { + static const VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R8G8B8A8_UINT, &CopyNativeVertexData); + return info; + } + case gl::VERTEX_FORMAT_UBYTE4_INT: + { + static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8B8A8_UINT, &CopyNativeVertexData); + return info; + } + + // GL_SHORT + case gl::VERTEX_FORMAT_SSHORT1_INT: + { + static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R16_SINT, &CopyNativeVertexData); + return info; + } + case gl::VERTEX_FORMAT_SSHORT2_INT: + { + static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16_SINT, &CopyNativeVertexData); + return info; + } + case gl::VERTEX_FORMAT_SSHORT3_INT: + { + static const VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16B16A16_SINT, &CopyNativeVertexData); + return info; + } + case gl::VERTEX_FORMAT_SSHORT4_INT: + { + static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16B16A16_SINT, &CopyNativeVertexData); + return info; + } + + // GL_UNSIGNED_SHORT + case gl::VERTEX_FORMAT_USHORT1_INT: + { + static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R16_UINT, &CopyNativeVertexData); + return info; + } + case gl::VERTEX_FORMAT_USHORT2_INT: + { + static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16_UINT, &CopyNativeVertexData); + return info; + } + case gl::VERTEX_FORMAT_USHORT3_INT: + { + static const VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16B16A16_UINT, &CopyNativeVertexData); + return info; + } + case gl::VERTEX_FORMAT_USHORT4_INT: + { + static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16B16A16_UINT, &CopyNativeVertexData); + return info; + } + + // GL_INT + case gl::VERTEX_FORMAT_SINT1_INT: + { + static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R32_SINT, &CopyNativeVertexData); + return info; + } + case gl::VERTEX_FORMAT_SINT2_INT: + { + static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32_SINT, &CopyNativeVertexData); + return info; + } + case gl::VERTEX_FORMAT_SINT3_INT: + { + static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32B32_SINT, &CopyNativeVertexData); + return info; + } + case gl::VERTEX_FORMAT_SINT4_INT: + { + static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32B32A32_SINT, &CopyNativeVertexData); + return info; + } + + // GL_UNSIGNED_INT + case gl::VERTEX_FORMAT_UINT1_INT: + { + static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R32_SINT, &CopyNativeVertexData); + return info; + } + case gl::VERTEX_FORMAT_UINT2_INT: + { + static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32_SINT, &CopyNativeVertexData); + return info; + } + case gl::VERTEX_FORMAT_UINT3_INT: + { + static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32B32_SINT, &CopyNativeVertexData); + return info; + } + case gl::VERTEX_FORMAT_UINT4_INT: + { + static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32B32A32_SINT, &CopyNativeVertexData); + 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); + 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); + 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 #include "common/platform.h" - -#include +#include "libANGLE/angletypes.h" +#include "libANGLE/formatutils.h" +#include "libANGLE/renderer/d3d/formatutilsD3D.h" namespace rx { +struct Renderer11DeviceCaps; namespace d3d11 { typedef std::map, 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 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 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; + } + default: + break; + } + } + case GL_RGB565: + { + switch (dxgiFormat) + { + case DXGI_FORMAT_R8G8B8A8_UNORM: + { + return Initialize4ComponentData; + } + default: + break; + } + } + case GL_SRGB8: + { + switch (dxgiFormat) + { + case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: + { + return Initialize4ComponentData; + } + default: + break; + } + } + case GL_RGB16F: + { + switch (dxgiFormat) + { + case DXGI_FORMAT_R16G16B16A16_FLOAT: + { + return Initialize4ComponentData; + } + default: + break; + } + } + case GL_RGB32F: + { + switch (dxgiFormat) + { + case DXGI_FORMAT_R32G32B32A32_FLOAT: + { + return Initialize4ComponentData; + } + default: + break; + } + } + case GL_RGB8UI: + { + switch (dxgiFormat) + { + case DXGI_FORMAT_R8G8B8A8_UINT: + { + return Initialize4ComponentData; + } + default: + break; + } + } + case GL_RGB8I: + { + switch (dxgiFormat) + { + case DXGI_FORMAT_R8G8B8A8_SINT: + { + return Initialize4ComponentData; + } + default: + break; + } + } + case GL_RGB16UI: + { + switch (dxgiFormat) + { + case DXGI_FORMAT_R16G16B16A16_UINT: + { + return Initialize4ComponentData; + } + default: + break; + } + } + case GL_RGB16I: + { + switch (dxgiFormat) + { + case DXGI_FORMAT_R16G16B16A16_SINT: + { + return Initialize4ComponentData; + } + default: + break; + } + } + case GL_RGB32UI: + { + switch (dxgiFormat) + { + case DXGI_FORMAT_R32G32B32A32_UINT: + { + return Initialize4ComponentData; + } + default: + break; + } + } + case GL_RGB32I: + { + switch (dxgiFormat) + { + case DXGI_FORMAT_R32G32B32A32_SINT: + { + return Initialize4ComponentData; + } + 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 + +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", + "dxgiFormat": "DXGI_FORMAT_R8G8_SNORM", + "requiresConversion": "false" + } + ] + }, + "GL_SRGB8": { + "GL_UNSIGNED_BYTE": [ + { + "loadFunction": "LoadToNative3To4", + "dxgiFormat": "DXGI_FORMAT_R8G8B8A8_UNORM_SRGB", + "requiresConversion": "true" + } + ] + }, + "GL_RGBA8I": { + "GL_BYTE": [ + { + "loadFunction": "LoadToNative", + "dxgiFormat": "DXGI_FORMAT_R8G8B8A8_SINT", + "requiresConversion": "false" + } + ] + }, + "GL_R8_SNORM": { + "GL_BYTE": [ + { + "loadFunction": "LoadToNative", + "dxgiFormat": "DXGI_FORMAT_R8_SNORM", + "requiresConversion": "false" + } + ] + }, + "GL_RGBA8_SNORM": { + "GL_BYTE": [ + { + "loadFunction": "LoadToNative", + "dxgiFormat": "DXGI_FORMAT_R8G8B8A8_SNORM", + "requiresConversion": "false" + } + ] + }, + "GL_R16I": { + "GL_SHORT": [ + { + "loadFunction": "LoadToNative", + "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", + "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", + "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", + "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", + "dxgiFormat": "DXGI_FORMAT_R32G32B32A32_UINT", + "requiresConversion": "false" + } + ] + }, + "GL_RG8UI": { + "GL_UNSIGNED_BYTE": [ + { + "loadFunction": "LoadToNative", + "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", + "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", + "dxgiFormat": "DXGI_FORMAT_R16_FLOAT", + "requiresConversion": "false" + } + ] + }, + "GL_RGBA8UI": { + "GL_UNSIGNED_BYTE": [ + { + "loadFunction": "LoadToNative", + "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", + "dxgiFormat": "DXGI_FORMAT_UNKNOWN", + "requiresConversion": "false" + } + ] + }, + "GL_RGBA16F": { + "GL_HALF_FLOAT": [ + { + "loadFunction": "LoadToNative", + "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", + "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", + "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", + "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", + "dxgiFormat": "DXGI_FORMAT_R32G32B32A32_FLOAT", + "requiresConversion": "false" + } + ] + }, + "GL_RGBA32I": { + "GL_INT": [ + { + "loadFunction": "LoadToNative", + "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", + "dxgiFormat": "DXGI_FORMAT_R8G8_UNORM", + "requiresConversion": "false" + } + ] + }, + "GL_RGB10_A2": { + "GL_UNSIGNED_INT_2_10_10_10_REV": [ + { + "loadFunction": "LoadToNative", + "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", + "dxgiFormat": "DXGI_FORMAT_R16_TYPELESS", + "requiresConversion": "false" + }, + { + "loadFunction": "LoadToNative", + "dxgiFormat": "DXGI_FORMAT_D16_UNORM", + "requiresConversion": "false" + } + ] + }, + "GL_RGB32I": { + "GL_INT": [ + { + "loadFunction": "LoadToNative3To4", + "dxgiFormat": "DXGI_FORMAT_R32G32B32A32_SINT", + "requiresConversion": "true" + } + ] + }, + "GL_R8": { + "GL_UNSIGNED_BYTE": [ + { + "loadFunction": "LoadToNative", + "dxgiFormat": "DXGI_FORMAT_R8_UNORM", + "requiresConversion": "false" + } + ] + }, + "GL_RGB32F": { + "GL_FLOAT": [ + { + "loadFunction": "LoadToNative3To4", + "dxgiFormat": "DXGI_FORMAT_R32G32B32A32_FLOAT", + "requiresConversion": "true" + } + ] + }, + "GL_R11F_G11F_B10F": { + "GL_UNSIGNED_INT_10F_11F_11F_REV": [ + { + "loadFunction": "LoadToNative", + "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", + "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", + "dxgiFormat": "DXGI_FORMAT_R16G16B16A16_SINT", + "requiresConversion": "false" + } + ] + }, + "GL_R8I": { + "GL_BYTE": [ + { + "loadFunction": "LoadToNative", + "dxgiFormat": "DXGI_FORMAT_R8_SINT", + "requiresConversion": "false" + } + ] + }, + "GL_RGB8_SNORM": { + "GL_BYTE": [ + { + "loadFunction": "LoadToNative3To4", + "dxgiFormat": "DXGI_FORMAT_R8G8B8A8_SNORM", + "requiresConversion": "true" + } + ] + }, + "GL_RG32F": { + "GL_FLOAT": [ + { + "loadFunction": "LoadToNative", + "dxgiFormat": "DXGI_FORMAT_R32G32_FLOAT", + "requiresConversion": "false" + } + ] + }, + "GL_DEPTH_COMPONENT32F": { + "GL_FLOAT": [ + { + "loadFunction": "LoadToNative", + "dxgiFormat": "DXGI_FORMAT_R32_TYPELESS", + "requiresConversion": "false" + }, + { + "loadFunction": "UnimplementedLoadFunction", + "dxgiFormat": "DXGI_FORMAT_UNKNOWN", + "requiresConversion": "true" + } + ] + }, + "GL_RG32I": { + "GL_INT": [ + { + "loadFunction": "LoadToNative", + "dxgiFormat": "DXGI_FORMAT_R32G32_SINT", + "requiresConversion": "false" + } + ] + }, + "GL_ALPHA8_EXT": { + "GL_UNSIGNED_BYTE": [ + { + "loadFunction": "LoadToNative", + "dxgiFormat": "DXGI_FORMAT_A8_UNORM", + "requiresConversion": "false" + }, + { + "loadFunction": "LoadA8ToRGBA8", + "dxgiFormat": "DXGI_FORMAT_R8G8B8A8_UNORM", + "requiresConversion": "true" + } + ] + }, + "GL_RG32UI": { + "GL_UNSIGNED_INT": [ + { + "loadFunction": "LoadToNative", + "dxgiFormat": "DXGI_FORMAT_R32G32_UINT", + "requiresConversion": "false" + } + ] + }, + "GL_RGBA16UI": { + "GL_UNSIGNED_SHORT": [ + { + "loadFunction": "LoadToNative", + "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", + "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", + "dxgiFormat": "DXGI_FORMAT_R32G8X24_TYPELESS", + "requiresConversion": "false" + }, + { + "loadFunction": "UnimplementedLoadFunction", + "dxgiFormat": "DXGI_FORMAT_UNKNOWN", + "requiresConversion": "true" + } + ] + }, + "GL_RG8I": { + "GL_BYTE": [ + { + "loadFunction": "LoadToNative", + "dxgiFormat": "DXGI_FORMAT_R8G8_SINT", + "requiresConversion": "false" + } + ] + }, + "GL_R32UI": { + "GL_UNSIGNED_INT": [ + { + "loadFunction": "LoadToNative", + "dxgiFormat": "DXGI_FORMAT_R32_UINT", + "requiresConversion": "false" + } + ] + }, + "GL_BGR5_A1_ANGLEX": { + "GL_UNSIGNED_BYTE": [ + { + "loadFunction": "LoadToNative", + "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", + "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", + "dxgiFormat": "DXGI_FORMAT_R16G16B16A16_SINT", + "requiresConversion": "true" + } + ] + }, + "GL_R8UI": { + "GL_UNSIGNED_BYTE": [ + { + "loadFunction": "LoadToNative", + "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", + "dxgiFormat": "DXGI_FORMAT_R16G16B16A16_FLOAT", + "requiresConversion": "true" + } + ], + "GL_FLOAT": [ + { + "loadFunction": "LoadRGB32FToRGBA16F", + "dxgiFormat": "DXGI_FORMAT_R16G16B16A16_FLOAT", + "requiresConversion": "true" + } + ], + "GL_HALF_FLOAT_OES": [ + { + "loadFunction": "LoadToNative3To4", + "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", + "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", + "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", + "dxgiFormat": "DXGI_FORMAT_R32_FLOAT", + "requiresConversion": "false" + } + ] + }, + "GL_RG16F": { + "GL_HALF_FLOAT": [ + { + "loadFunction": "LoadToNative", + "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", + "dxgiFormat": "DXGI_FORMAT_R16G16_FLOAT", + "requiresConversion": "false" + } + ] + }, + "GL_RGB565": { + "GL_UNSIGNED_BYTE": [ + { + "loadFunction": "LoadToNative3To4", + "dxgiFormat": "DXGI_FORMAT_R8G8B8A8_UNORM", + "requiresConversion": "true" + } + ], + "GL_UNSIGNED_SHORT_5_6_5": [ + { + "loadFunction": "LoadR5G6B5ToRGBA8", + "dxgiFormat": "DXGI_FORMAT_R8G8B8A8_UNORM", + "requiresConversion": "true" + }, + { + "loadFunction": "LoadToNative", + "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", + "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", + "dxgiFormat": "DXGI_FORMAT_R16G16_SINT", + "requiresConversion": "false" + } + ] + }, + "GL_BGRA8_EXT": { + "GL_UNSIGNED_BYTE": [ + { + "loadFunction": "LoadToNative", + "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", + "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", + "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", + "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 + +#include "libANGLE/renderer/d3d/d3d11/Renderer11.h" +#include "libANGLE/renderer/d3d/d3d11/texture_format_table.h" + +namespace rx +{ + +namespace d3d11 +{ + +const std::map &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 &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 loadFunctionsMap = []() { + std::map 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 loadFunctionsMap = []() { + std::map 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 loadFunctionsMap = []() { + std::map loadMap; + loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(UnreachableLoadFunction, true); + return loadMap; + }(); + + return loadFunctionsMap; + } + default: + { + static const std::map loadFunctionsMap = []() { + std::map 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 loadFunctionsMap = []() { + std::map 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 loadFunctionsMap = []() { + std::map 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 loadFunctionsMap = []() { + std::map loadMap; + loadMap[GL_FLOAT] = LoadImageFunctionInfo(LoadA32FToRGBA32F, true); + return loadMap; + }(); + + return loadFunctionsMap; + } + default: + { + static const std::map loadFunctionsMap = []() { + std::map 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 loadFunctionsMap = []() { + std::map loadMap; + loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadToNative, false); + return loadMap; + }(); + + return loadFunctionsMap; + } + case DXGI_FORMAT_R8G8B8A8_UNORM: + { + static const std::map loadFunctionsMap = []() { + std::map 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 loadFunctionsMap = []() { + std::map loadMap; + loadMap[GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT] = LoadImageFunctionInfo(LoadRGB5A1ToRGBA8, true); + loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadToNative, false); + return loadMap; + }(); + + return loadFunctionsMap; + } + default: + { + static const std::map loadFunctionsMap = []() { + std::map loadMap; + loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadToNative, 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 loadFunctionsMap = []() { + std::map loadMap; + loadMap[GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT] = LoadImageFunctionInfo(LoadRGBA4ToRGBA8, true); + loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadToNative, false); + return loadMap; + }(); + + return loadFunctionsMap; + } + default: + { + static const std::map loadFunctionsMap = []() { + std::map loadMap; + loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadToNative, 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 loadFunctionsMap = []() { + std::map loadMap; + loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadToNative, false); + return loadMap; + }(); + + return loadFunctionsMap; + } + default: + { + static const std::map loadFunctionsMap = []() { + std::map loadMap; + loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadToNative, true); + return loadMap; + }(); + + return loadFunctionsMap; + } + } + } + case GL_BGRA_EXT: + { + switch (dxgiFormat) + { + case DXGI_FORMAT_UNKNOWN: + { + static const std::map loadFunctionsMap = []() { + std::map loadMap; + loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(UnreachableLoadFunction, true); + return loadMap; + }(); + + return loadFunctionsMap; + } + default: + { + static const std::map loadFunctionsMap = []() { + std::map 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 loadFunctionsMap = []() { + std::map 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 loadFunctionsMap = []() { + std::map 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 loadFunctionsMap = []() { + std::map 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 loadFunctionsMap = []() { + std::map 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 loadFunctionsMap = []() { + std::map 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 loadFunctionsMap = []() { + std::map loadMap; + loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadCompressedToNative<4,4,8>, true); + return loadMap; + }(); + + return loadFunctionsMap; + } + default: + { + static const std::map loadFunctionsMap = []() { + std::map 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 loadFunctionsMap = []() { + std::map loadMap; + loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadCompressedToNative<4,4,16>, true); + return loadMap; + }(); + + return loadFunctionsMap; + } + default: + { + static const std::map loadFunctionsMap = []() { + std::map 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 loadFunctionsMap = []() { + std::map loadMap; + loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadCompressedToNative<4,4,16>, true); + return loadMap; + }(); + + return loadFunctionsMap; + } + default: + { + static const std::map loadFunctionsMap = []() { + std::map 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 loadFunctionsMap = []() { + std::map loadMap; + loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadCompressedToNative<4,4,8>, true); + return loadMap; + }(); + + return loadFunctionsMap; + } + default: + { + static const std::map loadFunctionsMap = []() { + std::map 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 loadFunctionsMap = []() { + std::map 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 loadFunctionsMap = []() { + std::map 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 loadFunctionsMap = []() { + std::map 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 loadFunctionsMap = []() { + std::map 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 loadFunctionsMap = []() { + std::map 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 loadFunctionsMap = []() { + std::map loadMap; + loadMap[GL_UNSIGNED_INT_24_8] = LoadImageFunctionInfo(LoadR32ToR24G8, true); + return loadMap; + }(); + + return loadFunctionsMap; + } + case DXGI_FORMAT_R24G8_TYPELESS: + { + static const std::map loadFunctionsMap = []() { + std::map 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 loadFunctionsMap = []() { + std::map loadMap; + loadMap[GL_FLOAT_32_UNSIGNED_INT_24_8_REV] = LoadImageFunctionInfo(LoadToNative, false); + return loadMap; + }(); + + return loadFunctionsMap; + } + case DXGI_FORMAT_UNKNOWN: + { + static const std::map loadFunctionsMap = []() { + std::map loadMap; + loadMap[GL_FLOAT_32_UNSIGNED_INT_24_8_REV] = LoadImageFunctionInfo(UnimplementedLoadFunction, true); + return loadMap; + }(); + + return loadFunctionsMap; + } + default: + { + static const std::map loadFunctionsMap = []() { + std::map 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 loadFunctionsMap = []() { + std::map loadMap; + loadMap[GL_UNSIGNED_SHORT] = LoadImageFunctionInfo(LoadToNative, false); + return loadMap; + }(); + + return loadFunctionsMap; + } + case DXGI_FORMAT_R16_TYPELESS: + { + static const std::map loadFunctionsMap = []() { + std::map loadMap; + loadMap[GL_UNSIGNED_INT] = LoadImageFunctionInfo(LoadR32ToR16, true); + loadMap[GL_UNSIGNED_SHORT] = LoadImageFunctionInfo(LoadToNative, false); + return loadMap; + }(); + + return loadFunctionsMap; + } + default: + break; + } + } + case GL_DEPTH_COMPONENT24: + { + switch (dxgiFormat) + { + case DXGI_FORMAT_D24_UNORM_S8_UINT: + { + static const std::map loadFunctionsMap = []() { + std::map loadMap; + loadMap[GL_UNSIGNED_INT] = LoadImageFunctionInfo(LoadR32ToR24G8, true); + return loadMap; + }(); + + return loadFunctionsMap; + } + case DXGI_FORMAT_R24G8_TYPELESS: + { + static const std::map loadFunctionsMap = []() { + std::map 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 loadFunctionsMap = []() { + std::map loadMap; + loadMap[GL_FLOAT] = LoadImageFunctionInfo(LoadToNative, false); + return loadMap; + }(); + + return loadFunctionsMap; + } + case DXGI_FORMAT_UNKNOWN: + { + static const std::map loadFunctionsMap = []() { + std::map loadMap; + loadMap[GL_FLOAT] = LoadImageFunctionInfo(UnimplementedLoadFunction, true); + return loadMap; + }(); + + return loadFunctionsMap; + } + default: + { + static const std::map loadFunctionsMap = []() { + std::map 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 loadFunctionsMap = []() { + std::map loadMap; + loadMap[GL_UNSIGNED_INT] = LoadImageFunctionInfo(LoadR32ToR24G8, true); + return loadMap; + }(); + + return loadFunctionsMap; + } + default: + { + static const std::map loadFunctionsMap = []() { + std::map 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 loadFunctionsMap = []() { + std::map 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 loadFunctionsMap = []() { + std::map 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 loadFunctionsMap = []() { + std::map 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 loadFunctionsMap = []() { + std::map 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 loadFunctionsMap = []() { + std::map loadMap; + loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(UnreachableLoadFunction, true); + return loadMap; + }(); + + return loadFunctionsMap; + } + default: + { + static const std::map loadFunctionsMap = []() { + std::map 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 loadFunctionsMap = []() { + std::map 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 loadFunctionsMap = []() { + std::map 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 loadFunctionsMap = []() { + std::map loadMap; + loadMap[GL_FLOAT] = LoadImageFunctionInfo(LoadL32FToRGBA32F, true); + return loadMap; + }(); + + return loadFunctionsMap; + } + default: + { + static const std::map loadFunctionsMap = []() { + std::map 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 loadFunctionsMap = []() { + std::map loadMap; + loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadLA8ToRGBA8, true); + return loadMap; + }(); + + return loadFunctionsMap; + } + default: + { + static const std::map loadFunctionsMap = []() { + std::map 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 loadFunctionsMap = []() { + std::map loadMap; + loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadL8ToRGBA8, true); + return loadMap; + }(); + + return loadFunctionsMap; + } + default: + { + static const std::map loadFunctionsMap = []() { + std::map 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 loadFunctionsMap = []() { + std::map 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 loadFunctionsMap = []() { + std::map 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 loadFunctionsMap = []() { + std::map loadMap; + loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(UnreachableLoadFunction, true); + return loadMap; + }(); + + return loadFunctionsMap; + } + default: + { + static const std::map loadFunctionsMap = []() { + std::map 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 loadFunctionsMap = []() { + std::map 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 loadFunctionsMap = []() { + std::map 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 loadFunctionsMap = []() { + std::map loadMap; + loadMap[GL_FLOAT] = LoadImageFunctionInfo(LoadLA32FToRGBA32F, true); + return loadMap; + }(); + + return loadFunctionsMap; + } + default: + { + static const std::map loadFunctionsMap = []() { + std::map 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 loadFunctionsMap = []() { + std::map 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, false); + return loadMap; + }(); + + return loadFunctionsMap; + } + default: + break; + } + } + case GL_R16F: + { + switch (dxgiFormat) + { + case DXGI_FORMAT_R16_FLOAT: + { + static const std::map loadFunctionsMap = []() { + std::map loadMap; + loadMap[GL_FLOAT] = LoadImageFunctionInfo(Load32FTo16F<1>, true); + loadMap[GL_HALF_FLOAT] = LoadImageFunctionInfo(LoadToNative, false); + loadMap[GL_HALF_FLOAT_OES] = LoadImageFunctionInfo(LoadToNative, false); + return loadMap; + }(); + + return loadFunctionsMap; + } + default: + break; + } + } + case GL_R16I: + { + switch (dxgiFormat) + { + case DXGI_FORMAT_R16_SINT: + { + static const std::map loadFunctionsMap = []() { + std::map loadMap; + loadMap[GL_SHORT] = LoadImageFunctionInfo(LoadToNative, false); + return loadMap; + }(); + + return loadFunctionsMap; + } + default: + break; + } + } + case GL_R16UI: + { + switch (dxgiFormat) + { + case DXGI_FORMAT_R16_UINT: + { + static const std::map loadFunctionsMap = []() { + std::map loadMap; + loadMap[GL_UNSIGNED_SHORT] = LoadImageFunctionInfo(LoadToNative, false); + return loadMap; + }(); + + return loadFunctionsMap; + } + default: + break; + } + } + case GL_R32F: + { + switch (dxgiFormat) + { + case DXGI_FORMAT_R32_FLOAT: + { + static const std::map loadFunctionsMap = []() { + std::map loadMap; + loadMap[GL_FLOAT] = LoadImageFunctionInfo(LoadToNative, false); + return loadMap; + }(); + + return loadFunctionsMap; + } + default: + break; + } + } + case GL_R32I: + { + switch (dxgiFormat) + { + case DXGI_FORMAT_R32_SINT: + { + static const std::map loadFunctionsMap = []() { + std::map loadMap; + loadMap[GL_INT] = LoadImageFunctionInfo(LoadToNative, false); + return loadMap; + }(); + + return loadFunctionsMap; + } + default: + break; + } + } + case GL_R32UI: + { + switch (dxgiFormat) + { + case DXGI_FORMAT_R32_UINT: + { + static const std::map loadFunctionsMap = []() { + std::map loadMap; + loadMap[GL_UNSIGNED_INT] = LoadImageFunctionInfo(LoadToNative, false); + return loadMap; + }(); + + return loadFunctionsMap; + } + default: + break; + } + } + case GL_R8: + { + switch (dxgiFormat) + { + case DXGI_FORMAT_R8_UNORM: + { + static const std::map loadFunctionsMap = []() { + std::map loadMap; + loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadToNative, false); + return loadMap; + }(); + + return loadFunctionsMap; + } + default: + break; + } + } + case GL_R8I: + { + switch (dxgiFormat) + { + case DXGI_FORMAT_R8_SINT: + { + static const std::map loadFunctionsMap = []() { + std::map loadMap; + loadMap[GL_BYTE] = LoadImageFunctionInfo(LoadToNative, false); + return loadMap; + }(); + + return loadFunctionsMap; + } + default: + break; + } + } + case GL_R8UI: + { + switch (dxgiFormat) + { + case DXGI_FORMAT_R8_UINT: + { + static const std::map loadFunctionsMap = []() { + std::map loadMap; + loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadToNative, false); + return loadMap; + }(); + + return loadFunctionsMap; + } + default: + break; + } + } + case GL_R8_SNORM: + { + switch (dxgiFormat) + { + case DXGI_FORMAT_R8_SNORM: + { + static const std::map loadFunctionsMap = []() { + std::map loadMap; + loadMap[GL_BYTE] = LoadImageFunctionInfo(LoadToNative, false); + return loadMap; + }(); + + return loadFunctionsMap; + } + default: + break; + } + } + case GL_RG16F: + { + switch (dxgiFormat) + { + case DXGI_FORMAT_R16G16_FLOAT: + { + static const std::map loadFunctionsMap = []() { + std::map loadMap; + loadMap[GL_FLOAT] = LoadImageFunctionInfo(Load32FTo16F<2>, true); + loadMap[GL_HALF_FLOAT] = LoadImageFunctionInfo(LoadToNative, false); + loadMap[GL_HALF_FLOAT_OES] = LoadImageFunctionInfo(LoadToNative, false); + return loadMap; + }(); + + return loadFunctionsMap; + } + default: + break; + } + } + case GL_RG16I: + { + switch (dxgiFormat) + { + case DXGI_FORMAT_R16G16_SINT: + { + static const std::map loadFunctionsMap = []() { + std::map loadMap; + loadMap[GL_SHORT] = LoadImageFunctionInfo(LoadToNative, false); + return loadMap; + }(); + + return loadFunctionsMap; + } + default: + break; + } + } + case GL_RG16UI: + { + switch (dxgiFormat) + { + case DXGI_FORMAT_R16G16_UINT: + { + static const std::map loadFunctionsMap = []() { + std::map loadMap; + loadMap[GL_UNSIGNED_SHORT] = LoadImageFunctionInfo(LoadToNative, false); + return loadMap; + }(); + + return loadFunctionsMap; + } + default: + break; + } + } + case GL_RG32F: + { + switch (dxgiFormat) + { + case DXGI_FORMAT_R32G32_FLOAT: + { + static const std::map loadFunctionsMap = []() { + std::map loadMap; + loadMap[GL_FLOAT] = LoadImageFunctionInfo(LoadToNative, false); + return loadMap; + }(); + + return loadFunctionsMap; + } + default: + break; + } + } + case GL_RG32I: + { + switch (dxgiFormat) + { + case DXGI_FORMAT_R32G32_SINT: + { + static const std::map loadFunctionsMap = []() { + std::map loadMap; + loadMap[GL_INT] = LoadImageFunctionInfo(LoadToNative, false); + return loadMap; + }(); + + return loadFunctionsMap; + } + default: + break; + } + } + case GL_RG32UI: + { + switch (dxgiFormat) + { + case DXGI_FORMAT_R32G32_UINT: + { + static const std::map loadFunctionsMap = []() { + std::map loadMap; + loadMap[GL_UNSIGNED_INT] = LoadImageFunctionInfo(LoadToNative, false); + return loadMap; + }(); + + return loadFunctionsMap; + } + default: + break; + } + } + case GL_RG8: + { + switch (dxgiFormat) + { + case DXGI_FORMAT_R8G8_UNORM: + { + static const std::map loadFunctionsMap = []() { + std::map loadMap; + loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadToNative, false); + return loadMap; + }(); + + return loadFunctionsMap; + } + default: + break; + } + } + case GL_RG8I: + { + switch (dxgiFormat) + { + case DXGI_FORMAT_R8G8_SINT: + { + static const std::map loadFunctionsMap = []() { + std::map loadMap; + loadMap[GL_BYTE] = LoadImageFunctionInfo(LoadToNative, false); + return loadMap; + }(); + + return loadFunctionsMap; + } + default: + break; + } + } + case GL_RG8UI: + { + switch (dxgiFormat) + { + case DXGI_FORMAT_R8G8_UINT: + { + static const std::map loadFunctionsMap = []() { + std::map loadMap; + loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadToNative, false); + return loadMap; + }(); + + return loadFunctionsMap; + } + default: + break; + } + } + case GL_RG8_SNORM: + { + switch (dxgiFormat) + { + case DXGI_FORMAT_R8G8_SNORM: + { + static const std::map loadFunctionsMap = []() { + std::map loadMap; + loadMap[GL_BYTE] = LoadImageFunctionInfo(LoadToNative, false); + return loadMap; + }(); + + return loadFunctionsMap; + } + default: + break; + } + } + case GL_RGB: + { + switch (dxgiFormat) + { + case DXGI_FORMAT_UNKNOWN: + { + static const std::map loadFunctionsMap = []() { + std::map 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 loadFunctionsMap = []() { + std::map 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 loadFunctionsMap = []() { + std::map loadMap; + loadMap[GL_UNSIGNED_INT_2_10_10_10_REV] = LoadImageFunctionInfo(LoadToNative, false); + return loadMap; + }(); + + return loadFunctionsMap; + } + default: + break; + } + } + case GL_RGB10_A2UI: + { + switch (dxgiFormat) + { + case DXGI_FORMAT_R10G10B10A2_UINT: + { + static const std::map loadFunctionsMap = []() { + std::map loadMap; + loadMap[GL_UNSIGNED_INT_2_10_10_10_REV] = LoadImageFunctionInfo(LoadToNative, false); + return loadMap; + }(); + + return loadFunctionsMap; + } + default: + break; + } + } + case GL_RGB16F: + { + switch (dxgiFormat) + { + case DXGI_FORMAT_R16G16B16A16_FLOAT: + { + static const std::map loadFunctionsMap = []() { + std::map loadMap; + loadMap[GL_FLOAT] = LoadImageFunctionInfo(LoadRGB32FToRGBA16F, true); + loadMap[GL_HALF_FLOAT] = LoadImageFunctionInfo(LoadToNative3To4, true); + loadMap[GL_HALF_FLOAT_OES] = LoadImageFunctionInfo(LoadToNative3To4, true); + return loadMap; + }(); + + return loadFunctionsMap; + } + default: + break; + } + } + case GL_RGB16I: + { + switch (dxgiFormat) + { + case DXGI_FORMAT_R16G16B16A16_SINT: + { + static const std::map loadFunctionsMap = []() { + std::map loadMap; + loadMap[GL_SHORT] = LoadImageFunctionInfo(LoadToNative3To4, true); + return loadMap; + }(); + + return loadFunctionsMap; + } + default: + break; + } + } + case GL_RGB16UI: + { + switch (dxgiFormat) + { + case DXGI_FORMAT_R16G16B16A16_UINT: + { + static const std::map loadFunctionsMap = []() { + std::map loadMap; + loadMap[GL_UNSIGNED_SHORT] = LoadImageFunctionInfo(LoadToNative3To4, true); + return loadMap; + }(); + + return loadFunctionsMap; + } + default: + break; + } + } + case GL_RGB32F: + { + switch (dxgiFormat) + { + case DXGI_FORMAT_R32G32B32A32_FLOAT: + { + static const std::map loadFunctionsMap = []() { + std::map loadMap; + loadMap[GL_FLOAT] = LoadImageFunctionInfo(LoadToNative3To4, true); + return loadMap; + }(); + + return loadFunctionsMap; + } + default: + break; + } + } + case GL_RGB32I: + { + switch (dxgiFormat) + { + case DXGI_FORMAT_R32G32B32A32_SINT: + { + static const std::map loadFunctionsMap = []() { + std::map loadMap; + loadMap[GL_INT] = LoadImageFunctionInfo(LoadToNative3To4, true); + return loadMap; + }(); + + return loadFunctionsMap; + } + default: + break; + } + } + case GL_RGB32UI: + { + switch (dxgiFormat) + { + case DXGI_FORMAT_R32G32B32A32_UINT: + { + static const std::map loadFunctionsMap = []() { + std::map loadMap; + loadMap[GL_UNSIGNED_INT] = LoadImageFunctionInfo(LoadToNative3To4, true); + return loadMap; + }(); + + return loadFunctionsMap; + } + default: + break; + } + } + case GL_RGB565: + { + switch (dxgiFormat) + { + case DXGI_FORMAT_B5G6R5_UNORM: + { + static const std::map loadFunctionsMap = []() { + std::map loadMap; + loadMap[GL_UNSIGNED_SHORT_5_6_5] = LoadImageFunctionInfo(LoadToNative, false); + return loadMap; + }(); + + return loadFunctionsMap; + } + case DXGI_FORMAT_R8G8B8A8_UNORM: + { + static const std::map loadFunctionsMap = []() { + std::map loadMap; + loadMap[GL_UNSIGNED_SHORT_5_6_5] = LoadImageFunctionInfo(LoadR5G6B5ToRGBA8, true); + loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadToNative3To4, true); + return loadMap; + }(); + + return loadFunctionsMap; + } + default: + break; + } + } + case GL_RGB5_A1: + { + switch (dxgiFormat) + { + case DXGI_FORMAT_B5G5R5A1_UNORM: + { + static const std::map loadFunctionsMap = []() { + std::map 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 loadFunctionsMap = []() { + std::map 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, false); + return loadMap; + }(); + + return loadFunctionsMap; + } + default: + break; + } + } + case GL_RGB8: + { + switch (dxgiFormat) + { + case DXGI_FORMAT_R8G8B8A8_UNORM: + { + static const std::map loadFunctionsMap = []() { + std::map loadMap; + loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadToNative3To4, true); + return loadMap; + }(); + + return loadFunctionsMap; + } + default: + break; + } + } + case GL_RGB8I: + { + switch (dxgiFormat) + { + case DXGI_FORMAT_R8G8B8A8_SINT: + { + static const std::map loadFunctionsMap = []() { + std::map loadMap; + loadMap[GL_BYTE] = LoadImageFunctionInfo(LoadToNative3To4, true); + return loadMap; + }(); + + return loadFunctionsMap; + } + default: + break; + } + } + case GL_RGB8UI: + { + switch (dxgiFormat) + { + case DXGI_FORMAT_R8G8B8A8_UINT: + { + static const std::map loadFunctionsMap = []() { + std::map loadMap; + loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadToNative3To4, true); + return loadMap; + }(); + + return loadFunctionsMap; + } + default: + break; + } + } + case GL_RGB8_SNORM: + { + switch (dxgiFormat) + { + case DXGI_FORMAT_R8G8B8A8_SNORM: + { + static const std::map loadFunctionsMap = []() { + std::map loadMap; + loadMap[GL_BYTE] = LoadImageFunctionInfo(LoadToNative3To4, true); + return loadMap; + }(); + + return loadFunctionsMap; + } + default: + break; + } + } + case GL_RGB9_E5: + { + switch (dxgiFormat) + { + case DXGI_FORMAT_R9G9B9E5_SHAREDEXP: + { + static const std::map loadFunctionsMap = []() { + std::map 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, false); + return loadMap; + }(); + + return loadFunctionsMap; + } + default: + break; + } + } + case GL_RGBA: + { + switch (dxgiFormat) + { + case DXGI_FORMAT_UNKNOWN: + { + static const std::map loadFunctionsMap = []() { + std::map 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 loadFunctionsMap = []() { + std::map 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 loadFunctionsMap = []() { + std::map loadMap; + loadMap[GL_FLOAT] = LoadImageFunctionInfo(Load32FTo16F<4>, true); + loadMap[GL_HALF_FLOAT] = LoadImageFunctionInfo(LoadToNative, false); + loadMap[GL_HALF_FLOAT_OES] = LoadImageFunctionInfo(LoadToNative, false); + return loadMap; + }(); + + return loadFunctionsMap; + } + default: + break; + } + } + case GL_RGBA16I: + { + switch (dxgiFormat) + { + case DXGI_FORMAT_R16G16B16A16_SINT: + { + static const std::map loadFunctionsMap = []() { + std::map loadMap; + loadMap[GL_SHORT] = LoadImageFunctionInfo(LoadToNative, false); + return loadMap; + }(); + + return loadFunctionsMap; + } + default: + break; + } + } + case GL_RGBA16UI: + { + switch (dxgiFormat) + { + case DXGI_FORMAT_R16G16B16A16_UINT: + { + static const std::map loadFunctionsMap = []() { + std::map loadMap; + loadMap[GL_UNSIGNED_SHORT] = LoadImageFunctionInfo(LoadToNative, false); + return loadMap; + }(); + + return loadFunctionsMap; + } + default: + break; + } + } + case GL_RGBA32F: + { + switch (dxgiFormat) + { + case DXGI_FORMAT_R32G32B32A32_FLOAT: + { + static const std::map loadFunctionsMap = []() { + std::map loadMap; + loadMap[GL_FLOAT] = LoadImageFunctionInfo(LoadToNative, false); + return loadMap; + }(); + + return loadFunctionsMap; + } + default: + break; + } + } + case GL_RGBA32I: + { + switch (dxgiFormat) + { + case DXGI_FORMAT_R32G32B32A32_SINT: + { + static const std::map loadFunctionsMap = []() { + std::map loadMap; + loadMap[GL_INT] = LoadImageFunctionInfo(LoadToNative, false); + return loadMap; + }(); + + return loadFunctionsMap; + } + default: + break; + } + } + case GL_RGBA32UI: + { + switch (dxgiFormat) + { + case DXGI_FORMAT_R32G32B32A32_UINT: + { + static const std::map loadFunctionsMap = []() { + std::map loadMap; + loadMap[GL_UNSIGNED_INT] = LoadImageFunctionInfo(LoadToNative, false); + return loadMap; + }(); + + return loadFunctionsMap; + } + default: + break; + } + } + case GL_RGBA4: + { + switch (dxgiFormat) + { + case DXGI_FORMAT_B4G4R4A4_UNORM: + { + static const std::map loadFunctionsMap = []() { + std::map 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 loadFunctionsMap = []() { + std::map loadMap; + loadMap[GL_UNSIGNED_SHORT_4_4_4_4] = LoadImageFunctionInfo(LoadRGBA4ToRGBA8, true); + loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadToNative, false); + return loadMap; + }(); + + return loadFunctionsMap; + } + default: + break; + } + } + case GL_RGBA8: + { + switch (dxgiFormat) + { + case DXGI_FORMAT_R8G8B8A8_UNORM: + { + static const std::map loadFunctionsMap = []() { + std::map loadMap; + loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadToNative, false); + return loadMap; + }(); + + return loadFunctionsMap; + } + default: + break; + } + } + case GL_RGBA8I: + { + switch (dxgiFormat) + { + case DXGI_FORMAT_R8G8B8A8_SINT: + { + static const std::map loadFunctionsMap = []() { + std::map loadMap; + loadMap[GL_BYTE] = LoadImageFunctionInfo(LoadToNative, false); + return loadMap; + }(); + + return loadFunctionsMap; + } + default: + break; + } + } + case GL_RGBA8UI: + { + switch (dxgiFormat) + { + case DXGI_FORMAT_R8G8B8A8_UINT: + { + static const std::map loadFunctionsMap = []() { + std::map loadMap; + loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadToNative, false); + return loadMap; + }(); + + return loadFunctionsMap; + } + default: + break; + } + } + case GL_RGBA8_SNORM: + { + switch (dxgiFormat) + { + case DXGI_FORMAT_R8G8B8A8_SNORM: + { + static const std::map loadFunctionsMap = []() { + std::map loadMap; + loadMap[GL_BYTE] = LoadImageFunctionInfo(LoadToNative, false); + return loadMap; + }(); + + return loadFunctionsMap; + } + default: + break; + } + } + case GL_SRGB8: + { + switch (dxgiFormat) + { + case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: + { + static const std::map loadFunctionsMap = []() { + std::map loadMap; + loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadToNative3To4, true); + return loadMap; + }(); + + return loadFunctionsMap; + } + default: + break; + } + } + case GL_SRGB8_ALPHA8: + { + switch (dxgiFormat) + { + case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: + { + static const std::map loadFunctionsMap = []() { + std::map loadMap; + loadMap[GL_UNSIGNED_BYTE] = LoadImageFunctionInfo(LoadToNative, false); + return loadMap; + }(); + + return loadFunctionsMap; + } + default: + break; + } + } + case GL_STENCIL_INDEX8: + { + switch (dxgiFormat) + { + case DXGI_FORMAT_UNKNOWN: + { + static const std::map loadFunctionsMap = []() { + std::map 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 loadFunctionsMap = []() { + std::map 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 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 + +#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 +#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::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::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(std::numeric_limits::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(std::numeric_limits::max() - 1); + caps->max3DTextureSize = static_cast(GetMaximum3DTextureSize(featureLevel)); + caps->max2DTextureSize = static_cast(GetMaximum2DTextureSize(featureLevel)); + caps->maxCubeMapTextureSize = static_cast(GetMaximumCubeMapTextureSize(featureLevel)); + caps->maxArrayTextureLayers = static_cast(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(GetMaximumSimultaneousRenderTargets(featureLevel)); + caps->maxColorAttachments = + static_cast(GetMaximumSimultaneousRenderTargets(featureLevel)); // D3D11 has the same limit for viewport width and height - caps->maxViewportWidth = GetMaximumViewportSize(featureLevel); + caps->maxViewportWidth = static_cast(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(GetMaximumDrawIndexedIndexCount(featureLevel)); + caps->maxElementsVertices = static_cast(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(GetMaximumVertexInputSlots(featureLevel)); + caps->maxVertexUniformComponents = + static_cast(GetMaximumVertexUniformVectors(featureLevel)) * 4; + caps->maxVertexUniformVectors = + static_cast(GetMaximumVertexUniformVectors(featureLevel)); + caps->maxVertexUniformBlocks = static_cast(GetMaximumVertexUniformBlocks(featureLevel)); + caps->maxVertexOutputComponents = + static_cast(GetMaximumVertexOutputVectors(featureLevel)) * 4; + caps->maxVertexTextureImageUnits = + static_cast(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(GetMaximumPixelUniformVectors(featureLevel)) * 4; + caps->maxFragmentUniformVectors = + static_cast(GetMaximumPixelUniformVectors(featureLevel)); + caps->maxFragmentUniformBlocks = + static_cast(GetMaximumPixelUniformBlocks(featureLevel)); + caps->maxFragmentInputComponents = + static_cast(GetMaximumPixelInputVectors(featureLevel)) * 4; + caps->maxTextureImageUnits = static_cast(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(std::numeric_limits::max()); -#if defined(ANGLE_ENABLE_D3D11_1) - ID3D11DeviceContext1 *deviceContext1 = d3d11::DynamicCastComObject(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(caps->maxVertexUniformBlocks) * static_cast(caps->maxUniformBlockSize / 4)) + static_cast(caps->maxVertexUniformComponents); caps->maxCombinedFragmentUniformComponents = (static_cast(caps->maxFragmentUniformBlocks) * static_cast(caps->maxUniformBlockSize / 4)) + static_cast(caps->maxFragmentUniformComponents); - caps->maxVaryingComponents = GetMaximumVertexOutputVectors(featureLevel) * 4; - caps->maxVaryingVectors = GetMaximumVertexOutputVectors(featureLevel); + caps->maxVaryingComponents = + static_cast(GetMaximumVertexOutputVectors(featureLevel)) * 4; + caps->maxVaryingVectors = static_cast(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(GetMaximumStreamOutputInterleavedComponents(featureLevel)); + caps->maxTransformFeedbackSeparateAttributes = + static_cast(GetMaximumStreamOutputBuffers(featureLevel)); + caps->maxTransformFeedbackSeparateComponents = + static_cast(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 *outSubresourceData, - std::vector< std::vector > *outData) +void GenerateInitialTextureData(GLint internalFormat, + const Renderer11DeviceCaps &renderer11DeviceCaps, + GLuint width, + GLuint height, + GLuint depth, + GLuint mipLevels, + std::vector *outSubresourceData, + std::vector> *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::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(strlen(multipleNamesUsed)), + multipleNamesUsed); + } + else + { + return resource->SetPrivateData(WKPDID_D3DDebugObjectName, + static_cast(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(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(genericResource); + newHelper.mTexture3D = d3d11::DynamicCastComObject(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(desc2D.Width); + mExtents.height = static_cast(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(desc3D.Width); + mExtents.height = static_cast(desc3D.Height); + mExtents.depth = static_cast(desc3D.Depth); + mFormat = desc3D.Format; + mSampleCount = 1; + } +} + +TextureHelper11::~TextureHelper11() +{ + SafeRelease(mTexture2D); + SafeRelease(mTexture3D); +} + +ID3D11Resource *TextureHelper11::getResource() const +{ + return mTexture2D ? static_cast(mTexture2D) + : static_cast(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 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 +#include + #include "libANGLE/angletypes.h" #include "libANGLE/Caps.h" #include "libANGLE/Error.h" - -#include +#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; 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 *outSubresourceData, - std::vector< std::vector > *outData); +void GenerateInitialTextureData(GLint internalFormat, + const Renderer11DeviceCaps &renderer11DeviceCaps, + GLuint width, + GLuint height, + GLuint depth, + GLuint mipLevels, + std::vector *outSubresourceData, + std::vector> *outData); + +UINT GetPrimitiveRestartIndex(); struct PositionTexCoordVertex { @@ -133,58 +161,230 @@ inline bool isDeviceLostError(HRESULT errorCode) } } -template -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 -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 -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 -inline void SetBufferData(ID3D11DeviceContext *context, ID3D11Buffer *constantBuffer, const T &value) +template +ID3D11PixelShader *CompilePS(ID3D11Device *device, const BYTE (&byteCode)[N], const char *name) +{ + return CompilePS(device, byteCode, N, name); +} + +template +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 +void LazyResource::checkAssociatedDevice(ID3D11Device *device) +{ + ASSERT(mAssociatedDevice == nullptr || device == mAssociatedDevice); + mAssociatedDevice = device; } -gl::Error GetAttachmentRenderTarget(const gl::FramebufferAttachment *attachment, RenderTarget11 **outRT); +template +class LazyShader final : public LazyResource +{ + 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::resolve(ID3D11Device *device) +{ + checkAssociatedDevice(device); + if (mResource == nullptr) + { + mResource = CompileVS(device, mByteCode, mByteCodeSize, mName); + } + return mResource; } +template <> +inline ID3D11GeometryShader *LazyShader::resolve(ID3D11Device *device) +{ + checkAssociatedDevice(device); + if (mResource == nullptr) + { + mResource = CompileGS(device, mByteCode, mByteCodeSize, mName); + } + return mResource; } +template <> +inline ID3D11PixelShader *LazyShader::resolve(ID3D11Device *device) +{ + checkAssociatedDevice(device); + if (mResource == nullptr) + { + mResource = CompilePS(device, mByteCode, mByteCodeSize, mName); + } + return mResource; +} + +class LazyInputLayout final : public LazyResource +{ + 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 mInputDesc; + size_t mByteCodeLen; + const BYTE *mByteCode; + const char *mDebugName; +}; + +class LazyBlendState final : public LazyResource +{ + 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 +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 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 +#include + +#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 + +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" + }, + { + "texFormat": "DXGI_FORMAT_B5G6R5_UNORM", + "srvFormat": "DXGI_FORMAT_B5G6R5_UNORM", + "rtvFormat": "DXGI_FORMAT_B5G6R5_UNORM", + "requirementsFcn": "SupportsFormat" + } + ], + "GL_RGB5_A1": [ + { + "texFormat": "DXGI_FORMAT_R8G8B8A8_UNORM", + "srvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM", + "rtvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM", + "requirementsFcn": "SupportsFormat" + }, + { + "texFormat": "DXGI_FORMAT_B5G5R5A1_UNORM", + "srvFormat": "DXGI_FORMAT_B5G5R5A1_UNORM", + "rtvFormat": "DXGI_FORMAT_B5G5R5A1_UNORM", + "requirementsFcn": "SupportsFormat" + } + ], + "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" + }, + { + "texFormat": "DXGI_FORMAT_B4G4R4A4_UNORM", + "srvFormat": "DXGI_FORMAT_B4G4R4A4_UNORM", + "rtvFormat": "DXGI_FORMAT_B4G4R4A4_UNORM", + "requirementsFcn": "SupportsFormat" + } + ], + "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 + +#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 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 +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(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(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(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(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(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(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 +#if !defined(__MINGW32__) +#include +#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( + GetProcAddress(dcomp, "DCompositionCreateDevice")); + if (!createDComp) + { + return E_INVALIDARG; + } + + if (!mDevice) + { + IDXGIDevice *dxgiDevice = d3d11::DynamicCastComObject(device); + HRESULT result = createDComp(dxgiDevice, __uuidof(IDCompositionDevice), + reinterpret_cast(&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(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(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(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(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 props = propertySet; ComPtr 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(coreWindowSize.cx * mSwapChainScale), static_cast(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& 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& 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 { 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 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 host = mHost.lock(); + if (host) + { + host->setRotationFlags(flags); + } + #endif + return S_OK; } - std::shared_ptr host = mHost.lock(); - if (host) - { - host->setRotationFlags(flags); - } -#endif - return S_OK; - } + private: std::weak_ptr mHost; }; -HRESULT GetCoreWindowSizeInPixels(const ComPtr& coreWindow, RECT *windowSize); +HRESULT GetCoreWindowSizeInPixels(const ComPtr& 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> &propertyMap, + const wchar_t *propertyName, + boolean *hasKey, + ComPtr &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>& propertyMap, const wchar_t *propertyName, SIZE *value, bool *valueExists) +HRESULT GetOptionalSizePropertyValue(const ComPtr> &propertyMap, + const wchar_t *propertyName, SIZE *value, bool *valueExists) { - if (!propertyMap || !propertyName || !value || !valueExists) + ComPtr 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(sizeValue.Width), static_cast(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> &propertyMap, + const wchar_t *propertyName, float *value, bool *valueExists) +{ ComPtr 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(sizeValue.Width), static_cast(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 *coreWindow = nullptr); bool IsSwapChainPanel(EGLNativeWindowType window, ComPtr *swapChainPanel = nullptr); bool IsEGLConfiguredPropertySet(EGLNativeWindowType window, ABI::Windows::Foundation::Collections::IPropertySet **propertySet = nullptr, IInspectable **inspectable = nullptr); -HRESULT GetOptionalSizePropertyValue(const ComPtr>& propertyMap, const wchar_t *propertyName, SIZE *value, bool *valueExists); +HRESULT GetOptionalPropertyValue(const ComPtr> &propertyMap, + const wchar_t *propertyName, + boolean *hasKey, + ComPtr &propertyValue); + +HRESULT GetOptionalSizePropertyValue(const ComPtr> &propertyMap, + const wchar_t *propertyName, SIZE *value, bool *valueExists); + +HRESULT GetOptionalSinglePropertyValue(const ComPtr> &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 #include +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 +struct AddFtmBase +{ + typedef Implements, T, FtmBase> Type; +}; + +template +HRESULT RunOnUIThread(CODE &&code, const ComPtr &dispatcher) +{ + ComPtr 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::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 props = propertySet; ComPtr 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 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(ConvertDipsToPixels(swapChainPanelSize.cx * mSwapChainScale)), + static_cast(ConvertDipsToPixels(swapChainPanelSize.cy * mSwapChainScale)) }; + } } } @@ -82,8 +196,8 @@ bool SwapChainPanelNativeWindow::initialize(EGLNativeWindowType window, IPropert bool SwapChainPanelNativeWindow::registerForSizeChangeEvents() { - ComPtr sizeChangedHandler; - ComPtr frameworkElement; + ComPtr sizeChangedHandler; + ComPtr frameworkElement; HRESULT result = Microsoft::WRL::MakeAndInitialize(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 frameworkElement; - if (SUCCEEDED(mSwapChainPanel.As(&frameworkElement))) + ComPtr 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 uiElement; - result = mSwapChainPanel.As(&uiElement); - ASSERT(SUCCEEDED(result)); - - Size currentSize; - result = uiElement->get_RenderSize(¤tSize); - 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 uiElement; + result = mSwapChainPanel.As(&uiElement); + ASSERT(SUCCEEDED(result)); + + Size currentSize; + result = uiElement->get_RenderSize(¤tSize); + 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 &swapChainPanel, RECT *windowSize, bool *scalingActive) +HRESULT GetSwapChainPanelSize( + const ComPtr &swapChainPanel, + const ComPtr &dispatcher, + SIZE *windowSize, float *scaleFactor) { - ComPtr uiElement; - ABI::Windows::Foundation::Size renderSize = { 0, 0 }; + ComPtr 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 mSwapChainPanel; + ComPtr mSwapChainPanelDispatcher; ComPtr> mPropertyMap; ComPtr mSwapChain; }; @@ -73,6 +83,9 @@ class SwapChainPanelSizeChangedHandler : std::weak_ptr mHost; }; -HRESULT GetSwapChainPanelSize(const ComPtr &swapChainPanel, RECT *windowSize, bool *scalingActive = nullptr); +HRESULT GetSwapChainPanelSize( + const ComPtr &swapChainPanel, + const ComPtr &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(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(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(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(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(area.width) == desc.Width && static_cast(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(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(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(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(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(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(input), inputRowPitch, 0, - reinterpret_cast(locked.pBits), locked.Pitch, 0); + reinterpret_cast(input) + inputSkipBytes, + inputRowPitch, 0, reinterpret_cast(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(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((rgb & 0xF800) >> 8); + unsigned char green = static_cast((rgb & 0x07E0) >> 3); + unsigned char blue = static_cast((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((argb & 0x7C00) >> 7); + unsigned char green = static_cast((argb & 0x03E0) >> 2); + unsigned char blue = static_cast((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((argb & 0x7C00) >> 7); + unsigned char green = static_cast((argb & 0x03E0) >> 2); + unsigned char blue = static_cast((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(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 +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(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 + 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(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 +#include + #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 -#include #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(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(&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(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 &forceSetSamplers = (type == gl::SAMPLER_PIXEL) ? mForceSetPixelSamplerStates : mForceSetVertexSamplerStates; - std::vector &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(texture); - // Make sure to add the level offset for our tiny compressed texture workaround - TextureD3D *textureD3D = GetImplAs(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(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 &appliedSerials = (type == gl::SAMPLER_PIXEL) ? mCurPixelTextureSerials : mCurVertexTextureSerials; + std::vector &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(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(d3dTexture)) { mDevice->SetTexture(d3dSampler, d3dTexture); } - appliedSerials[index] = serial; + appliedTextures[index] = reinterpret_cast(d3dTexture); return gl::Error(GL_NO_ERROR); } gl::Error Renderer9::setUniformBuffers(const gl::Data &/*data*/, - const GLint /*vertexUniformBuffers*/[], - const GLint /*fragmentUniformBuffers*/[]) + const std::vector &/*vertexUniformBuffers*/, + const std::vector &/*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(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(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(mRenderTargetDesc.width)); - rect.top = gl::clamp(scissor.y, 0, static_cast(mRenderTargetDesc.height)); - rect.right = gl::clamp(scissor.x + scissor.width, 0, static_cast(mRenderTargetDesc.width)); - rect.bottom = gl::clamp(scissor.y + scissor.height, 0, static_cast(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(mRenderTargetDesc.width)); - dxViewport.Y = gl::clamp(actualViewport.y, 0, static_cast(mRenderTargetDesc.height)); - dxViewport.Width = gl::clamp(actualViewport.width, 0, static_cast(mRenderTargetDesc.width) - static_cast(dxViewport.X)); - dxViewport.Height = gl::clamp(actualViewport.height, 0, static_cast(mRenderTargetDesc.height) - static_cast(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(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(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(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(indexInfo.indexRange.length()) + 1; - mDevice->DrawIndexedPrimitive(mPrimitiveType, -minIndex, minIndex, vertexCount, indexInfo.startIndex, mPrimitiveCount); + mDevice->DrawIndexedPrimitive(mPrimitiveType, -minIndex, minIndex, + static_cast(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(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(indices)[i]; + data[i] = static_cast(static_cast(indices)[i]); } - data[count] = static_cast(indices)[0]; + data[count] = static_cast(static_cast(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(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(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(mappedMemory); for (size_t i = 0; i < count; i++) { - data[i] = i; + data[i] = static_cast(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(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(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(program); + ProgramD3D *programD3D = GetImplAs(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(vertexExe)->getVertexShader() : nullptr); + IDirect3DPixelShader9 *pixelShader = (pixelExe ? GetAs(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 &uniformArray) +gl::Error Renderer9::applyUniforms(const ProgramD3D &programD3D, + GLenum /*drawMode*/, + const std::vector &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(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(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(mAdapterIdentifier.VendorId); + deviceIdentifier.DeviceId = static_cast(mAdapterIdentifier.DeviceId); + deviceIdentifier.SubSysId = static_cast(mAdapterIdentifier.SubSysId); + deviceIdentifier.Revision = static_cast(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(source); + RenderTarget9 *dest9 = GetAs(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 &transformFeedbackVaryings, - bool separatedOutputBuffers, ShaderExecutableD3D **outExecutable) +gl::Error Renderer9::loadExecutable(const void *function, + size_t length, + ShaderType type, + const std::vector &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 &transformFeedbackVaryings, - bool separatedOutputBuffers, const D3DCompilerWorkarounds &workarounds, +gl::Error Renderer9::compileToExecutable(gl::InfoLog &infoLog, + const std::string &shaderHLSL, + ShaderType type, + const std::vector &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(src); + Image9 *dst9 = GetAs(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(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(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(mDevice), + EGL_D3D9_DEVICE_ANGLE, EGL_FALSE); + + if (error.isError()) + { + SafeDelete(mEGLDevice); + return error; + } + } + + *device = static_cast(mEGLDevice); + return egl::Error(EGL_SUCCESS); +} + +Renderer9::CurSamplerState::CurSamplerState() + : forceSet(true), + baseLevel(std::numeric_limits::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 &vertexUniformBuffers, + const std::vector &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 &uniformArray); + gl::Error applyRenderTarget(const gl::FramebufferAttachment *colorAttachment, + const gl::FramebufferAttachment *depthStencilAttachment); + gl::Error applyUniforms(const ProgramD3D &programD3D, + GLenum drawMode, + const std::vector &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 &transformFeedbackVaryings, - bool separatedOutputBuffers, ShaderExecutableD3D **outExecutable); - virtual gl::Error compileToExecutable(gl::InfoLog &infoLog, const std::string &shaderHLSL, ShaderType type, - const std::vector &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 &streamOutVaryings, + bool separatedOutputBuffers, + ShaderExecutableD3D **outExecutable) override; + gl::Error compileToExecutable(gl::InfoLog &infoLog, + const std::string &shaderHLSL, + ShaderType type, + const std::vector &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 mForceSetVertexSamplerStates; - std::vector mCurVertexSamplerStates; + struct CurSamplerState + { + CurSamplerState(); - std::vector mForceSetPixelSamplerStates; - std::vector mCurPixelSamplerStates; + bool forceSet; + size_t baseLevel; + gl::SamplerState samplerState; + }; + std::vector mCurVertexSamplerStates; + std::vector mCurPixelSamplerStates; // Currently applied textures - std::vector mCurVertexTextureSerials; - std::vector mCurPixelTextureSerials; + std::vector mCurVertexTextures; + std::vector 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 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(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(mRenderTargetBounds.width); + actualViewport.height = static_cast(mRenderTargetBounds.height); + actualZNear = 0.0f; + actualZFar = 1.0f; + } + + D3DVIEWPORT9 dxViewport; + dxViewport.X = gl::clamp(actualViewport.x, 0, static_cast(mRenderTargetBounds.width)); + dxViewport.Y = gl::clamp(actualViewport.y, 0, static_cast(mRenderTargetBounds.height)); + dxViewport.Width = + gl::clamp(actualViewport.width, 0, + static_cast(mRenderTargetBounds.width) - static_cast(dxViewport.X)); + dxViewport.Height = + gl::clamp(actualViewport.height, 0, + static_cast(mRenderTargetBounds.height) - static_cast(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((actualViewport.width - static_cast(dxViewport.Width)) + + 2 * (actualViewport.x - static_cast(dxViewport.X)) - 1) / + dxViewport.Width; + vc.viewAdjust[1] = + static_cast((actualViewport.height - static_cast(dxViewport.Height)) + + 2 * (actualViewport.y - static_cast(dxViewport.Y)) - 1) / + dxViewport.Height; + vc.viewAdjust[2] = static_cast(actualViewport.width) / dxViewport.Width; + vc.viewAdjust[3] = static_cast(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(&mVertexConstants), + sizeof(dx_VertexConstants9) / sizeof(float[4])); + device->SetPixelShaderConstantF(0, reinterpret_cast(&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(mRenderTargetBounds.width)); + rect.top = gl::clamp(scissor.y, 0, static_cast(mRenderTargetBounds.height)); + rect.right = + gl::clamp(scissor.x + scissor.width, 0, static_cast(mRenderTargetBounds.width)); + rect.bottom = + gl::clamp(scissor.y + scissor.height, 0, static_cast(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(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(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(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 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(mWidth), static_cast(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(x), static_cast(mHeight - y - height), + static_cast(x + width), static_cast(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(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(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(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(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(mTextureWidth >> textureMipLevel, 1u); + size_t mipHeight = std::max(mTextureHeight >> textureMipLevel, 1u); + + baseTexture->AddRef(); + mRenderTargets[index.mipIndex] = new TextureRenderTarget9( + baseTexture, textureMipLevel, surface, mInternalFormat, static_cast(mipWidth), + static_cast(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(mTextureWidth), + static_cast(mTextureHeight), + static_cast(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(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(renderTargetD3D); + + mInternalFormat = renderTarget9->getInternalFormat(); + mTextureFormat = renderTarget9->getD3DFormat(); + mTextureWidth = renderTarget9->getWidth(); + mTextureHeight = renderTarget9->getHeight(); + mTopLevel = static_cast(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(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(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(destStorage); + + IDirect3DBaseTexture9 *destBaseTexture9 = nullptr; + gl::Error error = dest9->getBaseTexture(&destBaseTexture9); + if (error.isError()) + { + return error; + } + + IDirect3DTexture9 *destTexture9 = static_cast(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(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(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(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(mTextureWidth), static_cast(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(mTextureWidth), static_cast(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(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 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(vertexBuffer); -} - -gl::Error VertexBuffer9::storeVertexAttributes(const gl::VertexAttribute &attrib, const gl::VertexAttribCurrentValueData ¤tValue, - 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(gl::ComputeVertexAttributeStride(attrib)); + int elementSize = static_cast(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(buffer); - ASSERT(storage); - error = storage->getData(&input); - if (error.isError()) - { - return error; - } - input += static_cast(attrib.offset); - } - else - { - input = static_cast(attrib.pointer); - } - } - else - { - input = reinterpret_cast(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(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(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 ¤tValue, - 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 &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(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(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(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(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(stream); element->Offset = 0; - element->Type = d3d9VertexInfo.nativeFormat; + element->Type = static_cast(d3d9VertexInfo.nativeFormat); element->Method = D3DDECLMETHOD_DEFAULT; element->Usage = D3DDECLUSAGE_TEXCOORD; - element->UsageIndex = program->getSemanticIndex(i); + element->UsageIndex = static_cast(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 &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, ReadColor ); InsertD3DFormatInfo(&map, D3DFMT_A8, 8, 1, 1, 0, 0, 0, 8, 0, 0, 0, GL_ALPHA8_EXT, GenerateMip, ReadColor ); InsertD3DFormatInfo(&map, D3DFMT_A8L8, 16, 1, 1, 0, 0, 0, 8, 8, 0, 0, GL_LUMINANCE8_ALPHA8_EXT, GenerateMip, ReadColor ); - InsertD3DFormatInfo(&map, D3DFMT_A4R4G4B4, 16, 1, 1, 4, 4, 4, 4, 0, 0, 0, GL_BGRA4_ANGLEX, GenerateMip, ReadColor ); - InsertD3DFormatInfo(&map, D3DFMT_A1R5G5B5, 16, 1, 1, 5, 5, 5, 1, 0, 0, 0, GL_BGR5_A1_ANGLEX, GenerateMip, ReadColor ); + InsertD3DFormatInfo(&map, D3DFMT_A4R4G4B4, 16, 1, 1, 4, 4, 4, 4, 0, 0, 0, GL_BGRA4_ANGLEX, GenerateMip, ReadColor ); + InsertD3DFormatInfo(&map, D3DFMT_A1R5G5B5, 16, 1, 1, 5, 5, 5, 1, 0, 0, 0, GL_BGR5_A1_ANGLEX, GenerateMip, ReadColor ); InsertD3DFormatInfo(&map, D3DFMT_R5G6B5, 16, 1, 1, 5, 6, 5, 0, 0, 0, 0, GL_RGB565, GenerateMip, ReadColor ); InsertD3DFormatInfo(&map, D3DFMT_X8R8G8B8, 32, 1, 1, 8, 8, 8, 0, 0, 0, 0, GL_BGRA8_EXT, GenerateMip, ReadColor ); InsertD3DFormatInfo(&map, D3DFMT_A8R8G8B8, 32, 1, 1, 8, 8, 8, 8, 0, 0, 0, GL_BGRA8_EXT, GenerateMip, ReadColor ); @@ -475,16 +475,25 @@ template struct UseFallback { enum { type = T::fallback }; }; // and the D3DDECLTYPE member needed for the vertex declaration in declflag. template class PreferenceRule> struct Converter - : VertexDataConverter::type, - WidenRule >::type, size>, - ConversionRule >::type>, - DefaultVertexValues >::type>::type, normalized > > + : VertexDataConverter< + typename GLToCType::type, + WidenRule>::type, size>, + ConversionRule>::type>, + DefaultVertexValues>::type>::type, + normalized>> { private: - enum { d3dtype = PreferenceRule< VertexTypeMapping >::type }; - enum { d3dsize = WidenRule::finalWidth }; + enum + { + d3dtype = PreferenceRule>::type + }; + enum + { + d3dsize = WidenRule::finalWidth + }; public: enum { capflag = VertexTypeFlags::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 #include "common/platform.h" - -#include +#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(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 > +template > 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 ); InsertFormatWriteFunctionMapping(&map, GL_BGRA_EXT, GL_UNSIGNED_BYTE, WriteColor ); - InsertFormatWriteFunctionMapping(&map, GL_BGRA_EXT, GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT, WriteColor ); - InsertFormatWriteFunctionMapping(&map, GL_BGRA_EXT, GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_BGRA_EXT, GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_BGRA_EXT, GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT, WriteColor ); InsertFormatWriteFunctionMapping(&map, GL_SRGB_EXT, GL_UNSIGNED_BYTE, WriteColor ); InsertFormatWriteFunctionMapping(&map, GL_SRGB_ALPHA_EXT, GL_UNSIGNED_BYTE, WriteColor ); 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(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(gl::average(src1->R, src2->R)); + dst->G = static_cast(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(gl::average(src1->R, src2->R)); + dst->G = static_cast(gl::average(src1->G, src2->G)); + dst->B = static_cast(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(gl::average(src1->R, src2->R)); + dst->G = static_cast(gl::average(src1->G, src2->G)); + dst->B = static_cast(gl::average(src1->B, src2->B)); + dst->A = static_cast(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(((rgb & 0x001F) << 3) | ((rgb & 0x001F) >> 2)); + dest[4 * x + 1] = static_cast(((rgb & 0x07E0) >> 3) | ((rgb & 0x07E0) >> 9)); + dest[4 * x + 2] = static_cast(((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(((rgb & 0xF800) >> 8) | ((rgb & 0xF800) >> 13)); + dest[4 * x + 1] = static_cast(((rgb & 0x07E0) >> 3) | ((rgb & 0x07E0) >> 9)); + dest[4 * x + 2] = static_cast(((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(input, y, z, inputRowPitch, inputDepthPitch); + uint16_t *dest = OffsetDataPointer(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(((rgba & 0x00F0) << 0) | ((rgba & 0x00F0) >> 4)); + dest[4 * x + 1] = static_cast(((rgba & 0x0F00) >> 4) | ((rgba & 0x0F00) >> 8)); + dest[4 * x + 2] = static_cast(((rgba & 0xF000) >> 8) | ((rgba & 0xF000) >> 12)); + dest[4 * x + 3] = static_cast(((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(((rgba & 0xF000) >> 8) | ((rgba & 0xF000) >> 12)); + dest[4 * x + 1] = static_cast(((rgba & 0x0F00) >> 4) | ((rgba & 0x0F00) >> 8)); + dest[4 * x + 2] = static_cast(((rgba & 0x00F0) << 0) | ((rgba & 0x00F0) >> 4)); + dest[4 * x + 3] = static_cast(((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(((bgra & 0xF000) >> 8) | ((bgra & 0xF000) >> 12)); + dest[4 * x + 1] = static_cast(((bgra & 0x0F00) >> 4) | ((bgra & 0x0F00) >> 8)); + dest[4 * x + 2] = static_cast(((bgra & 0x00F0) << 0) | ((bgra & 0x00F0) >> 4)); + dest[4 * x + 3] = static_cast(((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(input, y, z, inputRowPitch, inputDepthPitch); + uint16_t *dest = OffsetDataPointer(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(((rgba & 0x003E) << 2) | ((rgba & 0x003E) >> 3)); + dest[4 * x + 1] = static_cast(((rgba & 0x07C0) >> 3) | ((rgba & 0x07C0) >> 8)); + dest[4 * x + 2] = static_cast(((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13)); + dest[4 * x + 3] = static_cast((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(((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13)); + dest[4 * x + 1] = static_cast(((rgba & 0x07C0) >> 3) | ((rgba & 0x07C0) >> 8)); + dest[4 * x + 2] = static_cast(((rgba & 0x003E) << 2) | ((rgba & 0x003E) >> 3)); + dest[4 * x + 3] = static_cast((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(((bgra & 0xF800) >> 8) | ((bgra & 0xF800) >> 13)); + dest[4 * x + 1] = static_cast(((bgra & 0x07C0) >> 3) | ((bgra & 0x07C0) >> 8)); + dest[4 * x + 2] = static_cast(((bgra & 0x003E) << 2) | ((bgra & 0x003E) >> 3)); + dest[4 * x + 3] = static_cast((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((rgba & 0x000003FF) >> 2); + dest[4 * x + 1] = static_cast((rgba & 0x000FFC00) >> 12); + dest[4 * x + 2] = static_cast((rgba & 0x3FF00000) >> 22); + dest[4 * x + 3] = static_cast(((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(gl::clamp(value, 0, 255)); + } + + static signed char clampSByte(int value) + { + return static_cast(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(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(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(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(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(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(curPixel); + + int ry = static_cast(j) * (rv - ro) + 2; + int gy = static_cast(j) * (gv - go) + 2; + int by = static_cast(j) * (bv - bo) + 2; + for (size_t i = 0; i < 4 && (x + i) < w; i++) + { + row[i] = createRGBA(((static_cast(i) * (rh - ro) + ry) >> 2) + ro, + ((static_cast(i) * (gh - go) + gy) >> 2) + go, + ((static_cast(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(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(rgba.R >> 3) << 11) | + (static_cast(rgba.G >> 2) << 5) | + (static_cast(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( + (static_cast(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( + (static_cast(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(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(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(input, y / 4, z, inputRowPitch, inputDepthPitch); + uint8_t *destRow = + OffsetDataPointer(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(input, y / 4, z, inputRowPitch, inputDepthPitch); + uint8_t *destRow = + OffsetDataPointer(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(input, y / 4, z, inputRowPitch, inputDepthPitch); + uint8_t *destRow = + OffsetDataPointer(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(input, y / 4, z, inputRowPitch, inputDepthPitch); + uint8_t *destRow = + OffsetDataPointer(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(input, y / 4, z, inputRowPitch, inputDepthPitch); + uint8_t *destRow = + OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + + for (size_t x = 0; x < width; x += 4) + { + const ETC2Block *sourceBlockAlpha = sourceRow + (x / 2); + sourceBlockAlpha->decodeAsSingleChannel( + reinterpret_cast(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 + +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 +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(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 , , , and 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(level)) == 0 || + texture->getHeight(GL_TEXTURE_2D, static_cast(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(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(level)) == 0 || + texture->getHeight(cubeMapFace, static_cast(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(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(level)) == 0 || + texture->getHeight(GL_TEXTURE_3D, static_cast(level)) == 0 || + texture->getDepth(GL_TEXTURE_3D, static_cast(level)) == 0) + { + return Error(EGL_BAD_PARAMETER, + "target 3D texture does not have a valid size at specified level."); + } + + if (static_cast(zOffset) >= + texture->getDepth(GL_TEXTURE_3D, static_cast(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(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(ComputeVertexAttributeStride(attrib)); + GLint64 maxVertexElement = 0; + + if (attrib.divisor > 0) + { + maxVertexElement = + static_cast(primcount) / static_cast(attrib.divisor); + } + else + { + maxVertexElement = static_cast(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(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(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(width) > formatInfo.compressedBlockWidth && width % formatInfo.compressedBlockWidth != 0) || - height < 0 || (static_cast(height) > formatInfo.compressedBlockHeight && height % formatInfo.compressedBlockHeight != 0)) + if (width < 0 || height < 0) { return false; } + if (CompressedTextureFormatRequiresExactSize(internalFormat)) + { + if ((static_cast(width) > formatInfo.compressedBlockWidth && + width % formatInfo.compressedBlockWidth != 0) || + (static_cast(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(samples) > context->getExtensions().maxSamples) + if (static_cast(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(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(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 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 ValidateBeginQuery(gl::Context *context, GLenum target, GLuint id) +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,45 +1187,219 @@ 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 (count < 0) + if (!context->getExtensions().occlusionQueryBoolean && + !context->getExtensions().disjointTimerQuery) { - context->recordError(Error(GL_INVALID_VALUE)); + 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) + { + context->recordError(Error(GL_INVALID_VALUE)); return false; } @@ -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(ComputeVertexAttributeStride(attrib)); - GLint64 maxVertexElement = 0; - - if (attrib.divisor > 0) - { - maxVertexElement = static_cast(primcount) / static_cast(attrib.divisor); - } - else - { - maxVertexElement = static_cast(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 &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(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(indices); - if (!elementArrayBuffer->getIndexRangeCache()->findRange(type, offset, count, indexRangeOut)) + Error error = + elementArrayBuffer->getIndexRange(type, static_cast(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(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(indexRangeOut->end) >= context->getCaps().maxElementIndex) { + context->recordError(Error(GL_INVALID_OPERATION, g_ExceedsMaxElementErrorMessage)); return false; } - return true; + if (!ValidateDrawAttribs(context, primcount, static_cast(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(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 &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(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 #include -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(const_cast(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 +#include 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(width) > (caps.max2DTextureSize >> level) || static_cast(height) > (caps.max2DTextureSize >> level) || - static_cast(depth) > (caps.maxArrayTextureLayers >> level)) + static_cast(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(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(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(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(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(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(dpy); + if (dpy == EGL_NO_DISPLAY || !Display::isValidDisplay(display)) { SetGlobalError(Error(EGL_BAD_DISPLAY)); return EGL_FALSE; } - Display *display = static_cast(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(dpy); + if (dpy == EGL_NO_DISPLAY || !Display::isValidDisplay(display)) { SetGlobalError(Error(EGL_BAD_DISPLAY)); return EGL_FALSE; } - Display *display = static_cast(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(filteredConfigs[i]); } } - *num_config = filteredConfigs.size(); + *num_config = static_cast(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(filteredConfigs[i]); } } - *num_config = filteredConfigs.size(); + *num_config = static_cast(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(dpy); gl::Context *context = static_cast(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 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(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); + 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); + 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(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(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(dpy); + gl::Context *context = static_cast(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(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(dpy); + Image *img = static_cast(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(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); + + 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(data)); + Error error = + texture->setCompressedImage(context, target, level, internalformat, size, imageSize, + reinterpret_cast(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(data)); + Error error = + texture->setCompressedSubImage(context, target, level, area, format, imageSize, + reinterpret_cast(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(texture->getWidth(baseTarget, 0))) || + !isPow2(static_cast(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(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("Google Inc."); - case GL_RENDERER: - return (GLubyte*)((context != NULL) ? context->getRendererString().c_str() : "ANGLE"); + case GL_RENDERER: + return reinterpret_cast(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( + "OpenGL ES 2.0 (ANGLE " ANGLE_VERSION_STRING ")"); + } + else + { + return reinterpret_cast( + "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( + "OpenGL ES GLSL ES 1.00 (ANGLE " ANGLE_VERSION_STRING ")"); + } + else + { + return reinterpret_cast( + "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(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(texture->immutableLevelCount()); + *params = static_cast(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(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(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(param); break; - case GL_TEXTURE_WRAP_T: texture->getSamplerState().wrapT = uiround(param); break; - case GL_TEXTURE_WRAP_R: texture->getSamplerState().wrapR = uiround(param); break; - case GL_TEXTURE_MIN_FILTER: texture->getSamplerState().minFilter = uiround(param); break; - case GL_TEXTURE_MAG_FILTER: texture->getSamplerState().magFilter = uiround(param); break; - case GL_TEXTURE_USAGE_ANGLE: texture->setUsage(uiround(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(param); break; - case GL_TEXTURE_COMPARE_FUNC: texture->getSamplerState().compareFunc = uiround(param); break; - case GL_TEXTURE_SWIZZLE_R: texture->getSamplerState().swizzleRed = uiround(param); break; - case GL_TEXTURE_SWIZZLE_G: texture->getSamplerState().swizzleGreen = uiround(param); break; - case GL_TEXTURE_SWIZZLE_B: texture->getSamplerState().swizzleBlue = uiround(param); break; - case GL_TEXTURE_SWIZZLE_A: texture->getSamplerState().swizzleAlpha = uiround(param); break; - case GL_TEXTURE_BASE_LEVEL: texture->getSamplerState().baseLevel = iround(param); break; - case GL_TEXTURE_MAX_LEVEL: texture->getSamplerState().maxLevel = iround(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(param)); break; + case GL_TEXTURE_WRAP_T: texture->setWrapT(uiround(param)); break; + case GL_TEXTURE_WRAP_R: texture->setWrapR(uiround(param)); break; + case GL_TEXTURE_MIN_FILTER: texture->setMinFilter(uiround(param)); break; + case GL_TEXTURE_MAG_FILTER: texture->setMagFilter(uiround(param)); break; + case GL_TEXTURE_USAGE_ANGLE: texture->setUsage(uiround(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(param)); break; + case GL_TEXTURE_COMPARE_FUNC: texture->setCompareFunc(uiround(param)); break; + case GL_TEXTURE_SWIZZLE_R: texture->setSwizzleRed(uiround(param)); break; + case GL_TEXTURE_SWIZZLE_G: texture->setSwizzleGreen(uiround(param)); break; + case GL_TEXTURE_SWIZZLE_B: texture->setSwizzleBlue(uiround(param)); break; + case GL_TEXTURE_SWIZZLE_A: texture->setSwizzleAlpha(uiround(param)); break; + case GL_TEXTURE_BASE_LEVEL: texture->setBaseLevel(uiround(param)); break; + case GL_TEXTURE_MAX_LEVEL: texture->setMaxLevel(uiround(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(param)); break; + case GL_TEXTURE_WRAP_T: texture->setWrapT(static_cast(param)); break; + case GL_TEXTURE_WRAP_R: texture->setWrapR(static_cast(param)); break; + case GL_TEXTURE_MIN_FILTER: texture->setMinFilter(static_cast(param)); break; + case GL_TEXTURE_MAG_FILTER: texture->setMagFilter(static_cast(param)); break; + case GL_TEXTURE_USAGE_ANGLE: texture->setUsage(static_cast(param)); break; + case GL_TEXTURE_MAX_ANISOTROPY_EXT: texture->setMaxAnisotropy(std::min(static_cast(param), context->getExtensions().maxTextureAnisotropy)); break; + case GL_TEXTURE_COMPARE_MODE: texture->setCompareMode(static_cast(param)); break; + case GL_TEXTURE_COMPARE_FUNC: texture->setCompareFunc(static_cast(param)); break; + case GL_TEXTURE_SWIZZLE_R: texture->setSwizzleRed(static_cast(param)); break; + case GL_TEXTURE_SWIZZLE_G: texture->setSwizzleGreen(static_cast(param)); break; + case GL_TEXTURE_SWIZZLE_B: texture->setSwizzleBlue(static_cast(param)); break; + case GL_TEXTURE_SWIZZLE_A: texture->setSwizzleAlpha(static_cast(param)); break; + case GL_TEXTURE_BASE_LEVEL: texture->setBaseLevel(static_cast(param)); break; + case GL_TEXTURE_MAX_LEVEL: texture->setMaxLevel(static_cast(param)); break; + case GL_TEXTURE_MIN_LOD: texture->setMinLod(static_cast(param)); break; + case GL_TEXTURE_MAX_LOD: texture->setMaxLod(static_cast(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(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; + } + + 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->drawArrays(mode, first, count, primcount); + 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 &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(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 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(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(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 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(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(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(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(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(bufSize) - 1, objectLabel.length()); + std::copy(objectLabel.begin(), objectLabel.begin() + writeLength, label); + label[writeLength] = '\0'; + *length = static_cast(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(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(bufSize) - 1, objectLabel.length()); + std::copy(objectLabel.begin(), objectLabel.begin() + writeLength, label); + label[writeLength] = '\0'; + *length = static_cast(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(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(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(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(data)); + Error error = + texture->setCompressedImage(context, target, level, internalformat, size, imageSize, + reinterpret_cast(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(data)); + Error error = + texture->setCompressedSubImage(context, target, level, area, format, imageSize, + reinterpret_cast(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(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(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(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(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(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(GL_SYNC_FENCE); break; case GL_SYNC_CONDITION: values[0] = static_cast(fenceSync->getCondition()); break; - case GL_SYNC_FLAGS: values[0] = 0; break; + case GL_SYNC_FLAGS: values[0] = static_cast(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(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(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(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 +#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 #include "common/platform.h" -#if _WIN32_WINNT_WINBLUE +#if _WIN32_WINNT_WINBLUE && WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP #include #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 -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 -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]; -- cgit v1.2.3